diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1114502a..9eb89965 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,8 +5,10 @@ version: 2 updates: - - package-ecosystem: "pip" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "uv" # See documentation for possible values + directories: + - "/" + - "/src" # Location of package manifests schedule: interval: "weekly" groups: diff --git a/docs/about/changelog.md b/docs/about/changelog.md index cb31527b..3b8d3f40 100644 --- a/docs/about/changelog.md +++ b/docs/about/changelog.md @@ -1,128 +1,6 @@ # Changelog -## Version 2024.3 Changelog - -In the 2024.3 release of the Stakeholder-Specific Vulnerability Classification (SSVC) system, we've made a number of significant changes: - -## New Web Site - -This release debuts the [certcc.github.io/SSVC](https://certcc.github.io/SSVC) web site to serve as the front-door for all things SSVC. - -- **Diátaxis Framework** - We adopted the [Diátaxis Framework](https://diataxis.fr/) as a document organization framework for SSVC documentation. High level content categories are: tutorials, how-to, topics, and reference. What used to be a linear paper format is now sectioned off into more digestible pieces. -- **More call-outs and examples** - With our adoption of [*Material for MkDocs*](https://squidfunk.github.io/mkdocs-material/) as the underlying toolkit to construct our web site, we were able to better highlight examples, tips, and sidebar topics through the use of call-out boxes throughout the site. - -## New and Revised Content - -- **Expanded Content** - We've included more examples of Decision Points and the like directly inline where they're mentioned so readers don't need to keep flipping back and forth to their definitions for reference. -- **Bootstrapping advice** - Added a *Getting Started with SSVC* process to help organizations go from being *potential* SSVC users to being *actual* SSVC users. This process is based on both our own experience helping organizations adopt SSVC as well as a few field reports of SSVC adoption from the community. -- **Putting the Pieces Together** - *Added a Putting the Pieces Together* page explaining some of our philosophy regarding how to use SSVC to model decisions. SSVC provides you with the pieces and some instructions on how to assemble them, but you can customize it however you like. -- **Acuity Ramp** - Added an *Acuity Ramp* explainer to show how an organization can grow into a decision model over time. -- **Community Engagement** - Included in the new web site are a number of suggested ways for the community to interact with and contribute to the SSVC. - -## Versioned Objects - -- **Semantic Versioning for Decision Points and Decision Point Groups** - Introduced Semantic Versioning (SemVer) for *Decision Points* and *Decision Point Groups* to improve communication around decision points and decision models -- **Calendar Versioning for SSVC as a whole** - With the introduction of SemVer for *Decision Points* and *Decision Point Groups*, it started to make less sense for us to talk in terms of "SSVC v2.2", especially as we were simultaneously moving away from a PDF document-focused development model towards a more flexible web-based documentation model. Beginning with this version, we anticipate that future tagged releases will use Calendar Versioning (CalVer) instead of SemVer. - -## Experimental & Emerging Features - -There are a few improvements we've begun but have not yet fully finished, and that are largely undocumented. Most of these in the current release are python-centric. Here's a brief overview for those who want to poke around at code. - -- **SSVC Python module** - This release introduces the `ssvc` python module to allow us to more easily work with *Decision Points*, *Decision Point Groups*, *Outcomes*, and *Policies* that map from *Decision Points* to *Outcomes*. We expect to have more to say about this module in the future, but for now it's geared towards helping us produce the site documentation. -- **Policy Generator** - We're prototyping a Python tool that can generate a starting policy given any combination of a *Decision Point Group* and *Outcomes*. It's not ready for prime-time yet, but folks with a bit of python skill might be in a position to try it out. -- **More Decision Points and Outcomes** - In the process of exercising our Semantic Versioning rules for decision points and groups, we needed some examples of versioning events for discussion purposes. As a result, the `ssvc.decision_points.cvss` and `ssvc.dp_groups.cvss` modules contain python implementations of CVSS vector elements from CVSS v1, v2, v3, v3.1, and v4. We anticipate some of these coming in handy in the future as we look toward modeling other decisions potentially based on CVSS vector elements as well as other decision points from SSVC and elsewhere. We also included decision points and groups from [CISA's customized SSVC implementation](https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc). - -## Other project infrastructure improvements - -- Shifted from PDF-oriented to web-oriented workflow -- Adopted [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) for static site production -- Adopted [Markdown Any Decision Records](https://adr.github.io/madr/) to preserve rationale and record decisions that are of significant impact to the project -- Added documentation to the [SSVC project wiki](https://github.com/CERTCC/SSVC/wiki) with tips for current and future contributors. -- Began using Github's [Dependabot](https://docs.github.com/en/code-security/dependabot) to help maintain dependency versions. - -## Version 2.1 (2023.7) Changelog - -This section summarizes the changes between SSVC 2.1 and SSVC version 2.0. -The details of what changes were made can be viewed on the SSVC Github under the SSVC v2.1 milestone. - -- Introduced a demo SSVC Calc App which became the basis for CISA's SSVC Calculator -- Updated Deployer tree to use *Automatable* instead of *Utility*, which reduced the size from 108 leaf nodes to 72. -- Adjusted Deployer tree decisions based on stakeholder feedback -- Adjusted Supplier tree decisions based on stakeholder feedback -- Added section on Sharing Trees With Others including a discussion of decision point scope and decision tree scope. -- Improved clarity of time-sensitivity of some decision points in Representing Information for Decisions About Vulnerabilities -- Improved description of *Mission Impact* -- Improved consistency of *Public Safety Impact* usage throughout the document and tooling -- Improved consistency of *Human Impact* usage throughout the document -- Clarified that known default passwords are an example of *Exploitation*:PoC -- Clarified that unreachable code (as in unused library features) are *System Exposure*:small -- Mention DoD MEF definition in *Mission Impact* -- Updated references to EPSS to reflect recent publications -- Refactored markdown files to better track chapter and section numbering, improving findability when editing -- Automated HTML and PDF generation into a Github Workflow -- Updated python tools to maintain sync with current SSVC decision models -- Consolidated the SSVC document style guide into a single file in the repository -- Miscellaneous typo fixes and readability improvements (e.g., headings, bulleted lists) - -## Version 2 (2021.5) Changelog - -This section summarizes the changes between SSVC version 2 and SSVC version 1.1 as published at the Workshop on the Ecnomics of Information Security (WEIS 2020). -The details of what changes were made can be viewed on the SSVC GitHub issues closed under the `SSVC v2 Development` project. -We addressed about 60 issues. -About 10 issues identified “bugs” or errors in version 1.1. -About 20 issues improved documentation of tools or improved the clarity of document text. -The remaining 30 issues were focused on enhancing SSVC based on feedback received on version 1, though several of the bug fixes and documentation improvements also provided improvements. -This section focuses on changes that provided enhancements. - -### Coordinator stakeholder - -Version 1 only considered two stakeholders: those who make software, and those who use information systems. -Version 2 introduces a coordinator stakeholder and two distinct decisions for that stakeholder group: vulnerability intake triage and publication about a vulnerability. -These decisions use some existing decision points, but also introduce six new decision points to support coordinators in making these decisions. -The coordinator stakeholder is based on CERT/CC's experience coordinating vulnerabilities. - -### Terminology changes - -Some terms have been adjusted to better align with other usage in the field or based on feedback. -Therefore, “patch developer” became **supplier** and “patch applier” became **deployer**. -These terms in version 2 better reflect the stakeholder's relationship to the vulnerable component and also help keep clear that SSVC is about prioritization of work items in vulnerability management, not just patches. -We have also generally removed the word patch and instead use the more general “remediation” for a complete fix and “mitigation” for actions that reduce risk but do not remove a vulnerability from a system. -“Virulence” was renamed *Automatable* in a effort to be more direct and clear, rather than relying on an epidemiology metaphor. -We changed “out-of-band” to **out-of-cycle**. - -Some concepts needed to be clarified or added. -These changes are a bit more substantive than the above terminology changes, but are similar. -For example, we clarified how end-of-life products are prioritized with SSVC. -We also clarified in Scope concepts around vulnerability identificatin and disambiguation. -Version 2 adopts an explicit definition of **risk** (from ISO Guide 73). -We also differentiated between vulnerability risk, or that risk arising from an unmanaged vulnerability in an information system, and change risk, or that risk from modifying or updating an information system to mitigate or remediate a vulnerability. -SSVC version 2 focuses on assessing and managing vulnerability risk, not change risk. -This stance was not explicit in SSVC version 1. - -### Improvements to decision points - -Version 1 had a decision point for well-being impact that was shared between **supplier** and **deployer** stakeholders. -Since these types of stakeholder have access to different information about safety and well-being, Version 2 splits this concept into *Public Safety Impact* and *Situated Safety Impact*. -The underlying definition remains largely the same. -However, *Public Safety Impact* has fewer output options (it is less granular) in recognition that a supplier or coordinator has less information about the context of deployment than a deployer does. - -In addition, based on feedback from SSVC users, the SSVC version 2 recommended applier tree makes use of a combined value for *Mission Impact* and *Situated Safety Impact*. -The intuition behind this change is that if a person is going to die OR the organization is going to fail (for example, go bankrupt), then the organization will likely want to act with highest priority. -Either situation is sufficient to increase the priority, and there do not appear to be situations where a low *Mission Impact* would mitigate a high *Situated Safety Impact* or vice versa. -On the other hand, a low *Utility* or *System Exposure* may mitigate a high mission or well-being impact. -So the Version 2 recommended tree is more usable than the Version 1 tree, thanks to these changes. - -### Tree management and communication tools - -The section Tree Construction and Customization Guidance is largely new or revised. -We produced new software tools for interacting with SSVC, which are documented in that section. -Version 2 adds reasoning behind why a stakeholder might customize a decision tree, what aspects of the tree are best to customize, tools for encoding custom trees in JSON, and scripts for visualizing custom trees. - -Similarly, the section on Guidance on Communicating Results is largely new. -The section presents both an abbreviated and unabridged format for communicating SSVC information about a vulnerability. -This communication may be connected to the formats for communicating a whole decision tree. -Version 2 also addresses several other questions about SSVC information management, such as handling information changes over time, partial information, sourcing information for each decision point, and how collection and analysis of SSVC decision points can be automated. - -## Version 1.0 (2019.12) Changelog - -Initial release +!!! note "See our change history on GitHub" + We’ve moved our changelog to GitHub to keep it accurate and up to date. + All past and current release notes are available on the [Releases page](https://github.com/CERTCC/SSVC/releases). + You can also view the [latest release](https://github.com/CERTCC/SSVC/releases/latest) directly. diff --git a/docs/ssvc-explorer/index.md b/docs/ssvc-explorer/index.md index c9e4bdfc..642912eb 100644 --- a/docs/ssvc-explorer/index.md +++ b/docs/ssvc-explorer/index.md @@ -1,22 +1,126 @@ --- hide: - - navigation - - title +- navigation +- title --- -# SSVC Policy Explorer +# SSVC Explorer +
+ - +
+

Would you like to proceed?

+ + +
+
+Sample Decision Models: + + + +
+ +  + +  + +
+
+SSVC Custom Trees + +Download (JSON) +Download (CSV) +
+ +
+

+

+
+

+
+ diff --git a/docs/ssvc-explorer/simple.js b/docs/ssvc-explorer/simple.js index 47369673..58228f6e 100644 --- a/docs/ssvc-explorer/simple.js +++ b/docs/ssvc-explorer/simple.js @@ -1,2589 +1,2616 @@ -const __version__ = "1.0.12"; -const SSVC = { - "outcomes": [], - "results": {}, - "decision_points": [], - "decision_trees" : [], - "form": null, - "dpMap":{}, - "default_namespace": "x_com.example#psirt", - "namespaces": [], - "__version__": __version__ -}; -function niceString(str) { - if (str.length) - return str.charAt(0).toUpperCase() + str.slice(1); - return ""; -} -function add_dash_n(str, strSet) { - if(!(str in strSet)) - return str; - const regex = /(-\d+)$/; - const match = str.match(regex); - let newNumber = -1; - let nstr = str + newNumber.toString(); - if (match) { - const numberPart = parseInt(match[1], 10); - newNumber = numberPart - 1; - nstr = str.replace(regex, newNumber.toString()); - } - while(nstr in strSet) { - newNumber = newNumber - 1; - nstr = str.replace(regex, newNumber.toString()); +const graphModule = (function() { + const showFullTree = true; + const acolors = [ "#28a745", "#72b741", "#b0c13f", "#e6be3d", "#ffc107", + "#fba145", "#f37d4f", "#e65b53", "#d93f4e", "#dc3545"]; + const lcolors = {}; + let raw; + let treeData; + let selector = '#graph'; + + function setSelector(newSelector) { + selector = newSelector; } - return nstr; -} -function name_version(obj) { - if(obj.name && obj.version) - return obj.name + " (" + obj.version + ")"; - else if (obj.name) - return obj.name + " (0.0.1)"; - else - return ""; -} -function dtreeSort(a, b) { - const nameA = a.data.namespace.toUpperCase() + a.data.name.toUpperCase() - + a.data.version.toUpperCase(); - const nameB = b.data.namespace.toUpperCase() + b.data.name.toUpperCase() - + b.data.version.toUpperCase(); - if (nameA < nameB) - return -1; - if (nameA > nameB) - return 1; - return 0; -} -function simpleCopy(inobj) { - return JSON.parse(JSON.stringify(inobj)); -} -window.addEventListener("beforeunload", function(e) { - if(sessionStorage.getItem("ssvc-pending")) { - var confirmationMessage = 'Are you sure to leave the page?'; - const event = (e || window.event); - event.preventDefault(); - event.returnValue = confirmationMessage; - return confirmationMessage; + + function create_raw(dt) { + const kmap = {}; + Object.entries(dt.decision_points).forEach(([k, v]) => { + kmap[k] = v.name; + }); + function find_value(k, dp) { + let dpm = dp.values.find(dpv => dpv.key == k); + if(dpm) + return dpm.name; + } + let thash = {}; + let dps = Object.keys(dt.decision_points); + let yraw = dps.map(x => []); + let zraw = []; + const final_k = dt.outcome; + const dpo = dt.decision_points[final_k]; + const ocolors = arrayReduce(acolors,dpo.values.length); + dpo.values.forEach(function(dpv,i) { + lcolors[dpv.name] = ocolors[i]; + }); + dt.decision_points[final_k].values.forEacj + const final_keyword = dt.decision_points[final_k].name; + const mapping = dt.mapping; + let id = 1; + for(let i=0; i find_value(dt.mapping[i][t],dt.decision_points[t])) + .slice(0,-1).join(":"); + for( let j=0; j< dps.length-1; j++) { + const tparent = dt.decision_points[dps[dps.length-2-j]].name + ":" + + dps.slice(0,dps.length-2-j).map(q => + find_value(dt.mapping[i][q],dt.decision_points[q])).join(":"); + if(!(tname in thash)) + var yt = {name:tname.replace(/\:+$/,''), + id:id++, + parent:tparent.replace(/\:+$/,''), + props:"{}",children:[]} + else + continue + thash[yt.name] = 1; + tname = tparent; + yraw[j].push(yt); + } + } + for(var j=yraw.length; j> -1; j--) { + if(yraw.length > 0) + zraw = zraw.concat(yraw[j]) + } + zraw[0] = {name:dt.decision_points[dps[0]].name,id:id+254,children:[],parent:null,props:"{}"} + return zraw; } - return null; -}); -function applyStyle(div, props) { - Object.entries(props).forEach(function(k,_) { - div.style[k[0]] = k[1]; - }); -} -function topalert(msg, level, timeOut) { - const colors = { - "danger": "#dc3545", - "info": "#0d6efd", - "warn": "#ffc107", - "success": "#198754" - }; - let div = document.querySelector("[data-topalert]"); - if (!div) { - div = document.createElement("div"); - div.setAttribute("data-topalert", "1"); - const props = { - width: "100%", - top: "0px", - left: "0px", - "text-align": "center", - color: "white", - border: "2px solid transparent", - "border-radius": "4px", - padding: "12px", - opacity: 0, - "font-size": "1.2em", - "transition": "opacity 0.5s ease", - "z-index": "9999", - "background-color": "transparent", - position: "relative" - }; - applyStyle(div, props); - document.body.prepend(div); - } + function grapharray_open(marray){ + var map = {}; + for(var i = 0; i < marray.length; i++){ + var obj = marray[i]; + obj.children= []; - if (!msg) { - div.style.opacity = 0; - div.style.backgroundColor = "transparent"; - div.innerHTML = ""; - return; + map[obj.name] = obj; + + var parent = obj.parent || '-'; + if(!map[parent]){ + map[parent] = { + children: [] + }; + } + map[parent].children.push(obj); + } + return map['-'].children; } - div.innerHTML = ""; - div.innerText = msg + " "; + function draw_graph() { + var margin = {top: 20, right: 120, bottom: 20, left: 120}, + width = 1060 - margin.right - margin.left, + height = 800 - margin.top - margin.bottom + if(showFullTree) { + var add_offset = 0 + if(raw.length > 60 ) + add_offset = (raw.length - 60)*5 + height = 1300 - margin.top - margin.bottom + add_offset + } + duration = 750 + tree = d3.layout.tree() + .size([height, width]); - const span = document.createElement("span"); - span.innerHTML = "✕"; - applyStyle(span, { - cursor: "pointer", - color: "white", - padding: "2px 6px", - border: "1px solid white", - "border-radius": "2px", - margin: "3px" - }); - div.appendChild(span); + diagonal = d3.svg.diagonal() + .projection(function(d) { return [d.y, d.x]; }); - div.onclick = () => div.remove(); + var default_translate = "translate(" + margin.left + "," + margin.top + ")" + var svg_width = width + margin.right + margin.left + var svg_height = height + margin.top + margin.bottom + if(window.innerWidth <= 1000) { + default_translate = "translate(10,0) scale(0.75)" + if(window.innerWidth <= 750) + default_translate = "translate(30,0) scale(0.42)" + } + let zdiv = $('
').css({position: "absolute"}); + let zinp = $('').attr({type: 'range', + min: '0', + max: '100', + value: '100', + accentColor: 'lightskyblue', + orient: 'vertical', + alt: 'Zoom Graph', + title: 'Zoom Graph'}); + zinp[0].onclick = function() { + const zf = this.value/this.max; + const fh = parseInt($('svg.mgraph').attr("height")); + const fw = parseInt($('svg.mgraph').attr("width")); + const vbox = "0 0 "+String(parseInt(fw/zf)) + " " + String(parseInt(fh/zf)) + $('svg.mgraph').attr('viewBox',vbox); + } + $(selector).html('').append(zdiv.append(zinp)); + svg = d3.select(selector).append("svg") + .attr("xmlns","http://www.w3.org/2000/svg") + .attr("preserveAspectRatio","none") + .attr("class","mgraph") + .attr("width", svg_width) + .attr("height", svg_height) + .append("g") + .attr("transform", default_translate) + .attr("id","pgroup"); - div.style.backgroundColor = colors[level] || colors["info"]; - div.style.display = "block"; - div.style.opacity = 0.95; + root = treeData[0]; + root.x0 = height / 2; + root.y0 = 0; - if (timeOut) { - if (div._timer) clearTimeout(div._timer); - div._timer = setTimeout(() => { - div.style.opacity = 0; - setTimeout(() => div.remove(), 600); - }, timeOut * 1000); + update(root) + + d3.select(self.frameElement).style("height", "700px"); } -} + function update(source) { + var i = 0 + var nodes = tree.nodes(root).reverse() + var links = tree.links(nodes) -function compareObj(o1,o2) { - const keys = Object.keys(o1); - if(keys.length != Object.keys(o2).length) - return false; - for(let i=0; i < keys.length; i++) { - const key = keys[i]; - if(o1[key] != o2[key]) { - return false; - } - } - return true; -} -function h5button(text, current, type) { - const h5 = document.createElement("h5"); - h5.innerText = text; - h5.style.display = "inline-block"; - if(current) - h5.style.backgroundColor = "#007bff"; - else - h5.style.backgroundColor = "#555555"; - h5.style.padding = "2px"; - h5.style.color = "white"; - h5.style.borderRadius = "4px"; - h5.setAttribute("data-tabs", type); - h5.addEventListener("click", function() { - const btn = this; - const current = btn.getAttribute("data-tabs"); - btn.parentElement.querySelectorAll("[data-tabs]").forEach(function(el) { - el.style.backgroundColor = "#555555"; - }); - btn.style.backgroundColor = "#007bff"; - btn.parentElement.querySelectorAll("[data-tab]").forEach(function(el) { - if(el.getAttribute("data-tab") == current) - el.style.display = "block"; - else - el.style.display = "none"; - }); - }); - return h5; -} -function rand_namespace(dtype) { - if(!dtype) - dtype = "generic" - return "x_example." + crypto.randomUUID() + "#" + dtype.toLowerCase(); -} -function lock_unlock(lock) { - const select = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - const btnAll = SSVC.form.parentElement.querySelector("[data-toggleall]"); - if(lock) { - const nextel = select.nextElementSibling; - /* Add custom data entry points */ - select.style.display = "none"; - select.parentElement.children[0].innerText = "Custom Decision Model"; - if(nextel.tagName.toUpperCase() == "DIV") { - const inp = nextel.querySelector("input[name='namespace'"); - if(inp) - inp.value = ""; - } else { - const div = document.createElement("div"); - const clbtn = SSVC.form.parentElement.querySelector("[data-clear]"); - let dt; - if(clbtn.hasAttribute("data-json")) { - dt = JSON.parse(clbtn.getAttribute("data-json")); - } else { - dt = {namespace: SSVC.default_namespace, - name: "Custom Decision Tree", - definition: "Uploaded Custom Decistion Tree from CSV", - version: "1.0.1"}; - } - div.style.display = "inline-block"; - applyStyle(div, {border: "1px dotted darkblue", - display: "inline-block", - borderRadius: "2px", - padding: "4px" - }); - ["name","namespace","definition","version"].forEach(function(nprop) { - const label = document.createElement("label"); - const input = document.createElement("input"); - input.name = nprop; - const nproper = niceString(nprop); - input.placeholder = "Decision Tree " + nproper; - if(nprop != "namespace") - input.value = dt[nprop]; - else - input.value = rand_namespace("decisiontables"); - applyStyle(input, {background: "transparent", - padding: "0px 2px", - display: "inline", - fontWeight: "bolder", - border: "1px solid #198754"}); - applyStyle(label, {display: "block", - textAlign: "right", - fontWeight: "bolder"}); - label.innerText = nproper + ": "; - label.append(input); - div.append(label); - - }); - select.after(div); - } - select.setAttribute("disabled", true); - btnAll.setAttribute("disabled", true); - btnAll.style.opacity = 0.5; - sessionStorage.setItem("ssvc-pending",1); - }else { - select.parentElement.children[0].innerText = "Sample Decision Models::"; - - if(select.nextElementSibling.nodeName.toUpperCase() == "DIV") { - select.nextElementSibling.remove(); - } - select.style.display = "inline-block"; - select.removeAttribute("disabled"); - btnAll.removeAttribute("disabled"); - btnAll.style.opacity = 1.0; - sessionStorage.removeItem("ssvc-pending"); - } - -} -function clear() { - const sampletrees = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - const nextel = sampletrees.nextElementSibling; - if(nextel.tagName.toUpperCase() == "DIV") - nextel.remove(); - sessionStorage.removeItem("ssvc-pending"); - sampletrees.style.display = "inline-block"; - sampletrees.disabled = false; - sampletrees.dispatchEvent(new Event('change')); - const cbtn = SSVC.form.parentElement.querySelector("[data-customize='1']"); - cbtn.innerHTML = "Customize"; - const btnAll = SSVC.form.parentElement.querySelector("[data-toggleall]"); - btnAll.disabled = false; - btnAll.style.opacity = 1.0; -} -function toNumberTable(table, headers) { - const encoders = {}; - const numberTable = table.map(function(row) { - return headers.reduce(function(r,head) { - const col = row[head]; - if(head in encoders) { - if (!(col in encoders[head])) { - const max = Math.max.apply(this,Object.values(encoders[head])); - encoders[head][col] = max + 1; + nodes.forEach(function(d) { d.y = d.depth * 200;}) + + var node = svg.selectAll("g.node") + .data(nodes, function(d) { return d.id || (d.id = ++i); }); + + var nodeEnter = node.enter().append("g") + .attr("class", "node bof") + .attr("transform", function(d) { + return "translate(" + source.y0 + "," + source.x0 + ")"; + }) + .attr("class", function(d) { + var finale = ""; + if(!('children' in d)) + finale = " finale"; + if('depth' in d) + return "node depth-"+String(d.depth)+finale; + return "node depth-none";}) + .on("click", doclick) + .on("contextmenu",dorightclick) + .on("mouseover",showdiv) + .on("mouseout",hidediv); + nodeEnter.append("circle") + .attr("r", 1e-6) + .attr("class",function(d, i) { + if(!('children' in d)) + return "junction gvisible finale "; + return "junction gvisible" + }) + .style("fill", function(d, i) { + if(d._children) return "lightsteelblue" + if(!('children' in d)) { + /* Last node no children */ + var dname = d.name.split(":").shift(); + if(dname in lcolors) + return undefined; } - } else { - encoders[head] = {}; - encoders[head][col] = 0; - } - r.push(encoders[head][row[head]]); - return r; - }, []); - }); - return numberTable; -} -function csvline(cols) { - cols = cols.map(x => x.replace('"','\\"')) - return '"' + cols.join('","') + '"\n'; -} -function get_decision_point(name, version, namespace) { - /* version 1.0.0 name mapping in CSV files */ - if(name in SSVC.dpMap && !version) { - version = SSVC.dpMap[name]["version"] - namespace = SSVC.dpMap[name]["namespace"]; - /* Check if name is remapped in CSVs*/ - if("name" in SSVC.dpMap[name]) - name = SSVC.dpMap[name]["name"]; - } - if(!version) - version = "1.0.0"; - if(!namespace) - namespace = "ssvc"; - for(let i = 0; i < SSVC.decision_points.length; i++) { - if(SSVC.decision_points[i].data.name == name && - SSVC.decision_points[i].data.namespace == namespace && - SSVC.decision_points[i].data.version == version) { - return SSVC.decision_points[i].data; - } - } - return {}; -} -function update_stats() { - SSVC.results = {}; - SSVC.form.querySelectorAll("[data-outcome]").forEach(function(el) { - let outcome; - if(el.querySelector("input")) - outcome = el.querySelector("input").value - else - outcome = el.innerText; - if(outcome in SSVC.results ) { - if(el.parentElement.style.display != "none") - SSVC.results[outcome] += 1; + return undefined; + } ); - } else { - if(el.parentElement.style.display != "none") - SSVC.results[outcome] = 1; - else - SSVC.results[outcome] = 0; - } - }); - - let outcomeMax = Math.max.apply(null, Object.values(SSVC.results)); - Object.keys(SSVC.results).forEach( function(outcome) { - outcome = outcome.replaceAll('"','\\"'); - let rlabel = SSVC.form.querySelector('[data-result="'+outcome+'"] > label > span'); - rlabel.innerText = " (" + String(SSVC.results[outcome]) + ")"; - let dbar = document.createElement("span"); - dbar.innerHTML = " "; - dbar.style.marginLeft = "6px"; - dbar.style.display = "inline-block"; - dbar.style.width = String(parseInt(70 * SSVC.results[outcome]/outcomeMax)) + "px"; - dbar.style.backgroundColor = "#5480de"; - /* dbar.style.position = "fixed"; */ - rlabel.appendChild(dbar); - - }); - const dtstamp = (new Date()).toISOString().replace(/[^0-9a-zA-Z]/g,"-") - const download_filename = "SSVC_Custom_" + dtstamp + "_json.txt"; - let clbutton = SSVC.form.parentElement.querySelector("[data-clear]"); - let jsonTreedump = clbutton.getAttribute("data-json"); - const btn = SSVC.form.parentElement.querySelector("[data-download-json]"); - btn.href = "data:text/plain;charset=utf-8,"+ - encodeURIComponent(jsonTreedump); - btn.setAttribute("download", download_filename); - const btncsv = SSVC.form.parentElement.querySelector("[data-download-csv]"); - let CSV = SSVC.form.parentElement.querySelector("[data-tab='CSV']").dataset.csv; - if(!CSV) { - /* Force render to ensure the elment is visible properly*/ - let tab = SSVC.form.parentElement.querySelector("[data-tab='CSV']"); - let oldv = tab.style.display; - tab.style.display = "block"; - CSV = SSVC.form.parentElement.querySelector("[data-tab='CSV']").innerText; - tab.style.display = oldv; - } - btncsv.href = "data:text/plain;charset=utf-8," + - encodeURIComponent(CSV); - const csv_filename = "SSVC_Custom_" + dtstamp + ".csv"; - btncsv.setAttribute("download", csv_filename); -} + var font = "20px" + if(showFullTree) + font = "18px" + nodeEnter.append("text") + .attr("x",function(d) { return check_children(d,"-55","+20") }) + .attr("y",function(d) { return check_children(d,"-37","0") }) + .attr("dy", ".35em") + .attr("class",function(d) { + var fclass = d.name.split(":").shift().toLowerCase(); + if(!('children' in d)) + return "gvisible prechk-"+fclass+" finale"; + return "gvisible prechk-"+fclass;}) + .text(function(d) { return d.name.split(":")[0]; }) + .style("font-size",font) + .style("fill", function(d) { + var t = d.name.split(":").shift(); + var x; + if(t in lcolors) + x = lcolors[t]; + return x; + }) -function createSSVC(csv, uploaded) { - SSVC.results = {}; - const exporter = { "ssvcV1_0_1": { - "id": "CVE-1999-1234", - "selections": [], - "timestamp": (new Date()).toISOString(), - "schemaVersion": "1-0-1" - }}; - const ssvcTable = []; - let jsonTree = {} - let CSV = ""; - let outcomeTitle; - let lines = []; - let headers = []; - let dset = []; - if(typeof(csv) === "object") { - /* This is JSON data more powerful use it */ - jsonTree = simpleCopy(csv); - if(('schemaVersion' in jsonTree) && - (jsonTree.schemaVersion === '2.0.0') && - ('decision_points' in jsonTree)) { - if(('outcome' in jsonTree) && - (jsonTree.outcome in jsonTree.decision_points)) - outcomeTitle = jsonTree.decision_points[jsonTree.outcome].name; - let hkeys = []; - SSVC.dpMap = {}; - let outcomeset = []; - Object.entries(jsonTree.decision_points).forEach(function([k,dp]) { - /* Dynamically build the name map per Tree. Assumption is there - are NO two decision points with the same name */ - if(dp.name in SSVC.dpMap) - topalert("danger", "Duplicate Names found in Decision Table can cause confusion", 0); - SSVC.dpMap[dp.name] = {name: dp.name, version: dp.version, - namespace: dp.namespace, data: dp}; - if(k != jsonTree.outcome) { - dset.push(dp.values.map(x => x.name)); - headers.push(dp.name); - hkeys.push(k); - } else { - /* Make sure the dset has the last entry as outcome*/ - outcomeset = dp.values.map(x => x.name); + /* hidden circle */ + nodeEnter.append("circle") + .attr("r","10") + .attr("class","ghidden d-none") + .style("fill","steelblue"); + + var nodeUpdate = node.transition() + .duration(duration) + .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); + + nodeUpdate.select("circle") + .attr("r", 10) + .attr("sid",function(d) { return d.id;}) + .attr("nameid",function(d) { if(!d) return "1"; + if(d.name) return d.name.split(":").pop(); + }) + .style("fill", function(d) { + if(d._children) return "lightsteelblue" + if(!('children' in d)) { + var dname = d.name.split(":").shift() + if(dname in lcolors) + return lcolors[dname]; + } + return undefined; + }) + .style("stroke",function(d) { + if(!('children' in d)) { + var dname = d.name.split(":").shift() + if(dname in lcolors) + return undefined; + } + return "steelblue"; + }) + + + nodeUpdate.select("text") + .style("fill-opacity", 1); + + var nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) + .remove(); + + nodeExit.select("circle") + .attr("r", 1e-6); + + nodeExit.select("text") + .style("fill-opacity", 1e-6); + + var link = svg.selectAll("path.link") + .data(links, function(d) { if(d.target) return d.target.id; }) + link.enter().insert("path","g") + .style("fill","none").style("stroke", "#ccc").attr("class","link") + .attr("id", function(d) { return 'l'+Math.random().toString(36).substr(3); }) + .attr("kdata", function(d) { return d.source.name.split(":").shift(); }) + .attr("ldata", function(d) { return d.target.name.split(":").pop(); }) + .attr("ldeep", function (d) { return d.target.name.split(":").length }) + .attr("csid",function(d) { return d.target.id;}) + .attr("d", function(d) { + var o = {x: source.x0, y: source.y0}; + return diagonal({source: o, target: o}); + }) + + link.transition() + .duration(duration) + .attr("d", diagonal); + + link.exit().transition() + .duration(duration) + .attr("d", function(d) { + var o = {x: source.x, y: source.y}; + return diagonal({source: o, target: o}); + }) + .remove(); + + nodes.forEach(function(d) { + d.x0 = d.x; + d.y0 = d.y; + }); + if(showFullTree === false) { + var d = source; + if(('depth' in d) && (!isNaN(parseInt(d.depth)))) { + $('g.depth-'+String(d.depth)+' .ghidden').addClass('d-none'); + $('g.depth-'+String(d.depth)+' .gvisible').show(); + $('g.depth-'+String(d.depth)).removeClass('opthide'); + var idepth = String(parseInt(d.depth) + 1) + if($('g.depth-'+idepth).length > 0) { + $('g.depth-'+idepth+' .ghidden').removeClass('d-none'); + $('g.depth-'+idepth+' .gvisible').hide(); + $('g.depth-'+idepth).addClass('opthide'); } - }); - dset.push(outcomeset); - headers.push(outcomeTitle); - hkeys.push(jsonTree.outcome); - if('mapping' in jsonTree) - jsonTree.mapping.forEach(function(dvpair) { - const line = hkeys.map(function(k) { - const vk = dvpair[k]; - const dp = jsonTree.decision_points[k]; - for(let i = 0; i < dp.values.length; i++) - if(dp.values[i].key == vk) - return dp.values[i].name; - }); - lines.push(line); - }); - } - } else { - lines = csv.split('\n'); - headers = lines.shift().split(','); - if(headers[0] == "row") { - /* CSV with row numbering setup so remove the first element*/ - headers.shift(); + } } + setTimeout(update_links,1500); + var xMin = d3.min(nodes, function(d) { return d.x; }); + var xMax = d3.max(nodes, function(d) { return d.x; }); + + var yOffset = 90; + var xOffset = -xMin + yOffset; + svg.attr("transform", "translate(" + 100 + "," + xOffset + ")"); } - const form = SSVC.form; - const main = document.createElement("main"); - function destroytip() { - let div = SSVC.form.querySelector("[data-temp]"); - if(div) - div.remove(); - } - function tooltip(event, info) { - let div = SSVC.form.querySelector("[data-temp]"); - if(!div) { - div = document.createElement("div"); - div.setAttribute("data-temp",1); - } - div.innerText = info; - const style = { - "display": "block", - "backgroundColor": "#333", - "opacity": "0.9", - "maxWidth": "300px", - "color": "white", - "borderRadius": "8px", - "position": "absolute", - "left": String(event.pageX + 10) + "px", - "top": String(event.pageY + 10) + "px", - "padding": "4px", - "border": "2px solid aqua" - }; - Object.assign(div.style,style); - SSVC.form.appendChild(div); + function check_children(d,a,b) { + if((d.children) && (d.children.length)) return a + if((d._children) && (d._children.length)) return a + return b } - function helptip(event) { - let dp = {}; - /* Check for Decision Point or Outcome and return helptip */ - const isdp = ["data-dp","data-outcomename"].some(function(fdp) { - if(event.target.hasAttribute(fdp)) { - /* A Decision Point help tip */ - dp = get_decision_point(event.target.getAttribute(fdp)); - if(dp.definition) { - tooltip(event, dp.definition); + + function arrayReduce(arr,n) { + if(n > arr.length) + return arr.concat(Array(n-arr.length).fill(arr.at(-1))) + return arr.filter(function(_,i) { + if (i === 0 || i === arr.length - 1) return true; + const step = (arr.length-1)/(n-1); + for (let j = 1; j < n - 1; j++) + if (Math.round(j * step) === i) return true; - } - } - /* This is more like continue */ return false; }); - if(isdp) - return false; - /* A Decision Point value helptip */ - const dpInput = event.target.querySelector("input"); - if(dpInput) { - if(dpInput.parentElement.parentElement.getAttribute("data-help")) { - dp = JSON.parse(dpInput.parentElement.parentElement.getAttribute("data-help")); - } else { - dp = get_decision_point(dpInput.name); - if(dp.definition) - dpInput.parentElement.parentElement.setAttribute("data-help",JSON.stringify(dp)); - } - } - if(dp.values) { - for(let i=0; i -1) { + xclass += " chosen" } - /* Add this except for last row - Last row is our results row. */ - vlabel.addEventListener("click", function(el) { - this.previousSibling.click(); - }); - inputDiv.append(input); - inputDiv.append(vlabel); - inputDiv.addEventListener("mouseenter", helptip); - inputDiv.addEventListener("mouseleave", destroytip); - div.append(inputDiv); + if(showFullTree) + xclass += " fullTree" + d3.select("g") + .insert("g","path.link").attr("class","pathlink cdepth-"+String(depth)).attr("id","x"+id) + .append("path").attr("d",xd).attr("id","f"+id) + .style("fill","none").style("stroke","#ccc") + .attr("class","xlink"); + var doffset = parseInt(70 - (4-depth)*5.5) + var yoffset = -10 + if(showFullTree) + yoffset = -6 + d3.select("g#x"+id).append("text").attr("dx",-6).attr("dy",yoffset).attr("class","gtext") + .append("textPath").attr("href","#f"+id).attr("class",xclass) + .attr("text-anchor","middle") + .attr("id","t"+id) + .attr("csid",csid) + .attr("parentname",pname) + .text(text).attr("startOffset",doffset+"%") + .on("click",pathclick) + .on("mouseover",showdiv) + .on("mouseout",hidediv); }); - main.appendChild(div); - }); - if(uploaded) { - /*Create Custom Decision Points and add them to popup */ - const newdps = Object.keys(ssvcTable[0]).reduce(function(ac,name) { - if(name != outcomeTitle) { - let version = "1.0.0"; - let namespace = "demo/custom" - ac[name] = {"filename": "memory:" + name , - "data": {"namespace": namespace, - "name": name, - "version": version, - "definition": name, - "schemaVersion": "1-0-1", - "values": [] - } - } + } + function graph_dynamic(input) { + const dpContainer = input.parentElement.parentElement.parentElement; + const finddpIndex = $(input).data("dpdepth"); + const nodes = d3.selectAll("g.node.depth-"+String(finddpIndex)); + function traverse_remove(xnode) { + if(!xnode.__data__) { + console.log("Error no nodes to descend!"); } - return ac; - }, {}); - ssvcTable.forEach(function(row) { - Object.keys(row).forEach(function(dpName) { - const value = row[dpName]; - if(newdps[dpName]) { - if(newdps[dpName].data.values.findIndex(function(nvalue) { - return nvalue.name == value;}) < 0) { - newdps[dpName].data.values.push({"name": value, "definition": value, "key": value[0]}); + if(!xnode.__data__._schildren) { + console.log("Error no node _schildren data to restore from!"); + } + let removeValues = []; + xnode.__data__.children = Array.from(xnode.__data__._schildren); + dpContainer.querySelectorAll("input").forEach(function(cinput) { + if(!cinput.checked) + removeValues.push($(cinput).data("dpvdepth")); + }); + removeValues.reverse().forEach(function(rindex) { + removevalueIndex = parseInt(rindex); + xnode.__data__.children.splice(removevalueIndex,1); + }); + update(xnode.__data__); + } + if(nodes.length) { + nodes[0].forEach(function(xnode) { + if(xnode.__data__) { + if(xnode.__data__._schildren) { + traverse_remove(xnode); + } else if(xnode.__data__.children) { + let removevalueIndex = $(input).data("dpvdepth"); + xnode.__data__._schildren = Array.from(xnode.__data__.children); + xnode.__data__.children.splice(removevalueIndex,1); + update(xnode.__data__); } } - }); - }); - /*Append new decision points */ - SSVC.decision_points.push.apply(SSVC.decision_points, - Object.values(newdps)); + } } + /* Helper function for advanced UI affects */ + function pathclick() {}; + function showdiv() {}; + function hidediv() {}; + function dorightclick() {}; + function doclick() {}; + function togglehelp() {}; + + + return { + pathclick:pathclick, + showdiv:showdiv, + hidediv:hidediv, + dorightclick:dorightclick, + doclick:doclick, + togglehelp:togglehelp, + graph_dynamic: graph_dynamic, + dt_graph: dt_graph, + setSelector: setSelector, + __version__: "1.0.10" + }; +})(); + +const SSVC = (function() { + let outcomes = []; + let results = {}; + let decision_points = []; + let decision_trees = []; + let form = null; + let dpMap = {}; + let default_namespace = "x_com.example#psirt"; + let namespaces = []; + let __version__ = "1.0.12"; - SSVC.decision_table = ssvcTable; - const numberTable = toNumberTable(SSVC.decision_table,Object.keys(SSVC.decision_table[0])); - const features = []; - const results = [] - numberTable.forEach(function(row) { - const outcome = row.pop(); - if(SSVC.results[outcome]) - SSVC.results[outcome] = SSVC.results[outcome] + 1; - else - SSVC.results[outcome] = 1; - results.push(outcome); - features.push(row); +function niceString(str) { + if (str.length) + return str.charAt(0).toUpperCase() + str.slice(1); + return ""; +} +function add_dash_n(str, strSet) { + if(!(str in strSet)) + return str; + const regex = /(-\d+)$/; + const match = str.match(regex); + let newNumber = -1; + let nstr = str + newNumber.toString(); + if (match) { + const numberPart = parseInt(match[1], 10); + newNumber = numberPart - 1; + nstr = str.replace(regex, newNumber.toString()); + } + while(nstr in strSet) { + newNumber = newNumber - 1; + nstr = str.replace(regex, newNumber.toString()); + } + return nstr; +} +function name_version(obj) { + if(obj.name && obj.version) + return obj.name + " (" + obj.version + ")"; + else if (obj.name) + return obj.name + " (0.0.1)"; + else + return ""; +} +function dtreeSort(a, b) { + const nameA = a.data.namespace.toUpperCase() + a.data.name.toUpperCase() + + a.data.version.toUpperCase(); + const nameB = b.data.namespace.toUpperCase() + b.data.name.toUpperCase() + + b.data.version.toUpperCase(); + if (nameA < nameB) + return -1; + if (nameA > nameB) + return 1; + return 0; +} +function simpleCopy(inobj) { + return JSON.parse(JSON.stringify(inobj)); +} +window.addEventListener("beforeunload", function(e) { + if(sessionStorage.getItem("ssvc-pending")) { + var confirmationMessage = 'Are you sure to leave the page?'; + const event = (e || window.event); + event.preventDefault(); + event.returnValue = confirmationMessage; + return confirmationMessage; + } + return null; +}); +function applyStyle(div, props) { + Object.entries(props).forEach(function(k,_) { + div.style[k[0]] = k[1]; }); - if(Object.keys(SSVC.results).length > 1) { - const labels = SSVC.decision_table.map(function(x) { - return x[outcomeTitle]; - }); - const featureImportance = computeFI(features,labels); - if(Object.keys(featureImportance).length == features[0].length) { - const pfdiv = document.createElement("div"); - pfdiv.style.display = "table-row"; - for(let i=0; i < features[0].length; i++) { - const fdiv = document.createElement("div"); - fdiv.innerText = featureImportance[i]['importance'].toFixed(4); - fdiv.style.display = "table-cell"; - fdiv.style.border = "1px solid cyan"; - pfdiv.appendChild(fdiv); - } - const fdiv = document.createElement("div"); - fdiv.innerText = "<= Feature Importance"; - pfdiv.appendChild(fdiv); - allrows.prepend(pfdiv); +} +function topalert(msg, level, timeOut) { + const colors = { + "danger": "#dc3545", + "info": "#0d6efd", + "warn": "#ffc107", + "success": "#198754" + }; + + let div = document.querySelector("[data-topalert]"); + if (!div) { + div = document.createElement("div"); + div.setAttribute("data-topalert", "1"); + const props = { + width: "100%", + top: "0px", + left: "0px", + "text-align": "center", + color: "white", + border: "2px solid transparent", + "border-radius": "4px", + padding: "12px", + opacity: 0, + "font-size": "1.2em", + "transition": "opacity 0.5s ease", + "z-index": "9999", + "background-color": "transparent", + position: "relative" + }; + applyStyle(div, props); + document.body.prepend(div); + } + + if (!msg) { + div.style.opacity = 0; + div.style.backgroundColor = "transparent"; + div.innerHTML = ""; + return; + } + + div.innerHTML = ""; + div.innerText = msg + " "; + + const span = document.createElement("span"); + span.innerHTML = "✕"; + applyStyle(span, { + cursor: "pointer", + color: "white", + padding: "2px 6px", + border: "1px solid white", + "border-radius": "2px", + margin: "3px" + }); + div.appendChild(span); + + div.onclick = () => div.remove(); + + div.style.backgroundColor = colors[level] || colors["info"]; + div.style.display = "block"; + div.style.opacity = 0.95; + + if (timeOut) { + if (div._timer) clearTimeout(div._timer); + div._timer = setTimeout(() => { + div.style.opacity = 0; + setTimeout(() => div.remove(), 600); + }, timeOut * 1000); + } +} + + +function compareObj(o1,o2) { + const keys = Object.keys(o1); + if(keys.length != Object.keys(o2).length) + return false; + for(let i=0; i < keys.length; i++) { + const key = keys[i]; + if(o1[key] != o2[key]) { + return false; } - } else { - console.log("There are no features to select importance from"); } - allrows.prepend(rowDiv); - allrows.style.display = "table"; - allrows.setAttribute("data-tab","table"); - form.appendChild(main); - form.appendChild(h5button("SSVC Table", "current", "table")); - form.appendChild (document.createTextNode (" ")); - form.appendChild(h5button("JSON", null, "JSON")); - form.appendChild (document.createTextNode (" ")); - form.appendChild(h5button("CSV", null, "CSV")); - form.appendChild (document.createTextNode (" ")); - form.appendChild(h5button("Graph", null, "GRAPH")); - const btn = SSVC.form.parentElement.querySelector("[data-clear]"); - btn.style.backgroundColor = "#dc3545"; - btn.style.color = "white"; - btn.innerText = " CLEAR "; - btn.type = "button"; - if(typeof(csv) == "object") - btn.setAttribute("data-json", JSON.stringify(csv,null,2)); + return true; +} +function h5button(text, current, type) { + const h5 = document.createElement("h5"); + h5.innerText = text; + h5.style.display = "inline-block"; + if(current) + h5.style.backgroundColor = "#007bff"; else - btn.setAttribute("data-csv", csv); - btn.addEventListener("click",clear); - form.appendChild(allrows); - const code = document.createElement("code"); - code.style.display = "none"; - code.style.border = "1px solid gray"; - code.style.width = "fit-content" - code.style.backgroundColor = "#eee"; - code.style.padding = "6px"; - code.style.whiteSpace = "pre-wrap"; - code.style.maxWidth = "90%"; - code.setAttribute("data-tab","JSON"); - code.innerText = JSON.stringify(jsonTree, null, 4); - form.appendChild(code); - const tcode = code.cloneNode(); - tcode.setAttribute("data-tab","CSV"); - tcode.innerText = CSV; - tcode.dataset.csv = CSV; - form.appendChild(tcode); - const tgraph = document.createElement("div"); - tgraph.id = "graph" - tgraph.setAttribute("data-tab","GRAPH"); - tgraph.style.display = "none"; - tgraph.innerText = "Graph not available for CSV data"; - form.appendChild(tgraph); - if(jsonTree.decision_points) - graphModule.dt_graph(csv); - function filterData(ev) { - exporter.ssvcV1_0_1.selections = []; - if(main.querySelectorAll("input:checked").length == 0) { - SSVC.form.querySelectorAll('[data-row]').forEach(function(row) { - row.style.display="none"; - }); - return update_stats(); - } - const div = ev.target.parentElement; - const ldivs = Array.from(SSVC.form.querySelectorAll("main > div")); - ldivs.pop(); - ldivs.forEach(function(div) { - div.style.opacity = 1.0; + h5.style.backgroundColor = "#555555"; + h5.style.padding = "2px"; + h5.style.color = "white"; + h5.style.borderRadius = "4px"; + h5.setAttribute("data-tabs", type); + h5.addEventListener("click", function() { + const btn = this; + const current = btn.getAttribute("data-tabs"); + btn.parentElement.querySelectorAll("[data-tabs]").forEach(function(el) { + el.style.backgroundColor = "#555555"; }); - if(div && div.hasAttribute("data-result")) { - const results = div.parentElement.querySelectorAll("input:checked"); - main.querySelectorAll("input").forEach(inp => inp.checked= false); - if(results.length == 0) { - SSVC.form.querySelectorAll('[data-row]').forEach(function(row) { - row.style.display="none"; - }); - return update_stats(); + btn.style.backgroundColor = "#007bff"; + btn.parentElement.querySelectorAll("[data-tab]").forEach(function(el) { + if(el.getAttribute("data-tab") == current) + el.style.display = "block"; + else + el.style.display = "none"; + }); + }); + return h5; +} +function rand_namespace(dtype) { + if(!dtype) + dtype = "generic" + return "x_example." + crypto.randomUUID() + "#" + dtype.toLowerCase(); +} +function lock_unlock(lock) { + const select = form.parentElement.querySelector("[id='sampletrees']"); + const btnAll = form.parentElement.querySelector("[data-toggleall]"); + if(lock) { + const nextel = select.nextElementSibling; + /* Add custom data entry points */ + select.style.display = "none"; + select.parentElement.children[0].innerText = "Custom Decision Model"; + if(nextel.tagName.toUpperCase() == "DIV") { + const inp = nextel.querySelector("input[name='namespace'"); + } else { + const div = document.createElement("div"); + const clbtn = form.parentElement.querySelector("[data-clear]"); + let dt; + if(clbtn.hasAttribute("data-json")) { + dt = JSON.parse(clbtn.getAttribute("data-json")); + } else { + dt = {namespace: default_namespace, + name: "Custom Decision Tree", + definition: "Uploaded Custom Decistion Tree from CSV", + version: "1.0.1"}; } - /* This is clicking on outcome be wary */ - topalert("When filtering by Outcome the Decision Point values can look confounded!","warn",4); - ldivs.forEach(function(div) { - div.style.opacity = 0.6; - }); - let counter = 0; - ssvcTable.forEach(function(mrow,i) { - let row = simpleCopy(mrow); - let drows = SSVC.form.querySelectorAll("[data-row]"); - drows[i].style.display = "none"; - results.forEach(function(result) { - result.checked = true; - result.parentElement.style.opacity = 1.0; - if(row[result.name] == result.value) { - counter++; - drows[i].style.display = "table-row"; - delete row[result.name]; - Object.entries(row).forEach(function([dpname,dpvalue]) { - let sel = 'input[name="'+dpname + - '"][value="'+dpvalue+'"]'; - let inp = SSVC.form.querySelector(sel); - if(inp) - inp.checked = true; - }); - } - }); + div.style.display = "inline-block"; + applyStyle(div, {border: "1px dotted darkblue", + display: "inline-block", + borderRadius: "2px", + padding: "4px" + }); + ["name","namespace","definition","version"].forEach(function(nprop) { + const label = document.createElement("label"); + const input = document.createElement("input"); + input.name = nprop; + const nproper = niceString(nprop); + input.placeholder = "Decision Tree " + nproper; + if(nprop != "namespace") + input.value = dt[nprop]; + else + input.value = rand_namespace("decisiontables"); + applyStyle(input, {background: "transparent", + padding: "0px 2px", + display: "inline", + fontWeight: "bolder", + border: "1px solid #198754"}); + applyStyle(label, {display: "block", + textAlign: "right", + fontWeight: "bolder"}); + label.innerText = nproper + ": "; + label.append(input); + div.append(label); + }); - const h5 = form.querySelector("h5"); - let text = String(counter) + " of " + String(ssvcTable.length) - h5.innerText = "-- SSVC Table (selected " + text + ") -- "; - return update_stats(); + select.after(div); } - if(ev.target && ev.target.tagName.toUpperCase() == "INPUT" - && ev.target.type.toLowerCase() == "checkbox") { - graphModule.graph_dynamic(ev.target); + select.setAttribute("disabled", true); + btnAll.setAttribute("disabled", true); + btnAll.style.opacity = 0.5; + sessionStorage.setItem("ssvc-pending",1); + }else { + select.parentElement.children[0].innerText = "Sample Decision Models::"; + + if(select.nextElementSibling.nodeName.toUpperCase() == "DIV") { + select.nextElementSibling.remove(); } - main.querySelectorAll("[data-result]").forEach(function(result) { - result.style.fontWeight = "normal"; - result.style.opacity = "0.6"; - const inp = result.querySelector("input"); - if(inp) - inp.checked = false; - }); - const selections = {}; - main.querySelectorAll("input:checked").forEach(function(input) { - const div = input.parentElement; - /*Ignoore outcome checkboxes that are checked */ - if(div && div.hasAttribute("data-result")) - return; - if(input.name in selections) - selections[input.name].push(input.value); - else - selections[input.name] = [input.value]; - }); - let rows = ssvcTable; - Object.keys(selections).forEach(function(decision_point) { - const dp = get_decision_point(decision_point); - exporter.ssvcV1_0_1.selections.push({"namespace": dp.namespace || "ssvc", - "version": dp.version || "1.0.0", - "values": selections[decision_point], - "name": decision_point}); - let chosen = selections[decision_point]; - rows = rows.filter(function(row) { - if(chosen.includes(row[decision_point])){ - if(outcomeTitle in row) { - return row; - } - } - }); - }); - form.querySelectorAll("[data-row]").forEach(function(trow) { - trow.style.display = "none"; - }); - rows.forEach(function(row) { - form.querySelectorAll("[data-row]").forEach(function(trow) { - let crow = JSON.parse(trow.getAttribute("data-row")); - if(compareObj(crow,row)) - trow.style.display = "table-row"; - }); - const rowTitle = row[outcomeTitle].replaceAll('"','\\"'); - main.querySelectorAll('[data-result="'+rowTitle+'"]').forEach(function(result) { - result.style.fontWeight = "bolder"; - result.style.opacity = "1.0"; - const inp = result.querySelector("input"); - if(inp) - inp.checked = true; - }); - }); - const h5 = form.querySelector("h5"); - let text = String(rows.length) + " of " + String(ssvcTable.length) - h5.innerText = "-- SSVC Table (selected " + text + ") -- "; - exporter.ssvcV1_0_1.timestamp = (new Date()).toISOString(); - /* always display JSON Tree - code.innerHTML = JSON.stringify(exporter, null, 4); - */ - update_stats(); + select.style.display = "inline-block"; + select.removeAttribute("disabled"); + btnAll.removeAttribute("disabled"); + btnAll.style.opacity = 1.0; + sessionStorage.removeItem("ssvc-pending"); } - main.addEventListener('change', filterData); - update_stats(); + +} +function clear() { + const sampletrees = form.parentElement.querySelector("[id='sampletrees']"); + const nextel = sampletrees.nextElementSibling; + if(nextel.tagName.toUpperCase() == "DIV") + nextel.remove(); + sessionStorage.removeItem("ssvc-pending"); + sampletrees.style.display = "inline-block"; + sampletrees.disabled = false; + sampletrees.dispatchEvent(new Event('change')); + const cbtn = form.parentElement.querySelector("[data-customize='1']"); + cbtn.innerHTML = "Customize"; + const btnAll = form.parentElement.querySelector("[data-toggleall]"); + btnAll.disabled = false; + btnAll.style.opacity = 1.0; } - - -function calculateEntropy(decision_table, targetCol) { - const valueCounts = {}; - decision_table.forEach(row => { - const value = row[targetCol]; - valueCounts[value] = (valueCounts[value] || 0) + 1; - }); - - const totalCount = decision_table.length; - let entropy = 0; - for (const count of Object.values(valueCounts)) { - const p = count / totalCount; - entropy -= p * Math.log2(p); - } - return entropy; +function toNumberTable(table, headers) { + const encoders = {}; + const numberTable = table.map(function(row) { + return headers.reduce(function(r,head) { + const col = row[head]; + if(head in encoders) { + if (!(col in encoders[head])) { + const max = Math.max.apply(this,Object.values(encoders[head])); + encoders[head][col] = max + 1; + } + } else { + encoders[head] = {}; + encoders[head][col] = 0; + } + r.push(encoders[head][row[head]]); + return r; + }, []); + }); + return numberTable; } - -function calculateInformationGain(decision_table,featureCol, targetCol) { - const totalEntropy = calculateEntropy(decision_table, targetCol); - const featureSet = new Set(decision_table.map(row => row[featureCol])); - const featureValues = Array.from(featureSet); - - let weightedEntropy = 0; - featureValues.forEach(value => { - const subset = decision_table.filter(row => row[featureCol] === value); - const subsetEntropy = calculateEntropy(subset, targetCol); - const subsetWeight = subset.length / decision_table.length; - weightedEntropy += subsetWeight * subsetEntropy; - }); - - return totalEntropy - weightedEntropy; +function csvline(cols) { + cols = cols.map(x => x.replace('"','\\"')) + return '"' + cols.join('","') + '"\n'; } - -/* const entropyMain = calculateEntropy(SSVC.decision_table, outcome); */ -/* calculateInformationGain(SSVC.decision_table, decision_point, outcome); */ - -function loadSSVC(fileurl) { - SSVC.form.innerHTML = ""; - if(fileurl == "upload_file") { - SSVC.form.parentElement.querySelector("input[type='file']").click(); - return; - } - if(fileurl.indexOf("csv:") == 0) { - /* fileurl itself is the payload with csv: in the front*/ - return createSSVC(fileurl.substring(4)); - } - if(fileurl.indexOf("json:") == 0) { - /* fileurl itself is the payload with json: in the front*/ - return createSSVC(JSON.parse(fileurl.substring(5))); +function get_decision_point(name, version, namespace) { + /* version 1.0.0 name mapping in CSV files */ + if(name in dpMap && !version) { + version = dpMap[name]["version"] + namespace = dpMap[name]["namespace"]; + /* Check if name is remapped in CSVs*/ + if("name" in dpMap[name]) + name = dpMap[name]["name"]; } - if(fileurl.match(/^\d+$/)) { - const index = parseInt(fileurl); - if( index in SSVC.decision_trees && SSVC.decision_trees[index].data) { - /* This is a SSVC.decision_point index find it and return */ - return createSSVC(SSVC.decision_trees[index].data); + if(!version) + version = "1.0.0"; + if(!namespace) + namespace = "ssvc"; + for(let i = 0; i < decision_points.length; i++) { + if(decision_points[i].data.name == name && + decision_points[i].data.namespace == namespace && + decision_points[i].data.version == version) { + return decision_points[i].data; } } - fetch(fileurl).then(function(d) { - d.text().then(function(csv) { - try { - const json = JSON.parse(csv); - createSSVC(json); - }catch(err) { - console.log("Assuming the uplaoded document is CSV"); - createSSVC(csv); - } - }); + return {}; +} +function update_stats() { + results = {}; + form.querySelectorAll("[data-outcome]").forEach(function(el) { + let outcome; + if(el.querySelector("input")) + outcome = el.querySelector("input").value + else + outcome = el.innerText; + if(outcome in results ) { + if(el.parentElement.style.display != "none") + results[outcome] += 1; + + } else { + if(el.parentElement.style.display != "none") + results[outcome] = 1; + else + results[outcome] = 0; + } + }); + + let outcomeMax = Math.max.apply(null, Object.values(results)); + Object.keys(results).forEach( function(outcome) { + outcome = outcome.replaceAll('"','\\"'); + let rlabel = form.querySelector('[data-result="'+outcome+'"] > label > span'); + rlabel.innerText = " (" + String(results[outcome]) + ")"; + let dbar = document.createElement("span"); + dbar.innerHTML = " "; + dbar.style.marginLeft = "6px"; + dbar.style.display = "inline-block"; + dbar.style.width = String(parseInt(70 * results[outcome]/outcomeMax)) + "px"; + dbar.style.backgroundColor = "#5480de"; + /* dbar.style.position = "fixed"; */ + rlabel.appendChild(dbar); + }); + const dtstamp = (new Date()).toISOString().replace(/[^0-9a-zA-Z]/g,"-") + const download_filename = "SSVC_Custom_" + dtstamp + "_json.txt"; + let clbutton = form.parentElement.querySelector("[data-clear]"); + let jsonTreedump = clbutton.getAttribute("data-json"); + const btn = form.parentElement.querySelector("[data-download-json]"); + btn.href = "data:text/plain;charset=utf-8,"+ + encodeURIComponent(jsonTreedump); + btn.setAttribute("download", download_filename); + const btncsv = form.parentElement.querySelector("[data-download-csv]"); + let CSV = form.parentElement.querySelector("[data-tab='CSV']").dataset.csv; + if(!CSV) { + /* Force render to ensure the elment is visible properly*/ + let tab = form.parentElement.querySelector("[data-tab='CSV']"); + let oldv = tab.style.display; + tab.style.display = "block"; + CSV = form.parentElement.querySelector("[data-tab='CSV']").innerText; + tab.style.display = oldv; + } + btncsv.href = "data:text/plain;charset=utf-8," + + encodeURIComponent(CSV); + const csv_filename = "SSVC_Custom_" + dtstamp + ".csv"; + btncsv.setAttribute("download", csv_filename); } -async function get_decision_points() { - /* Use the URL registry = await response.json(); */ - const response = await fetch("https://raw.githubusercontent.com/CERTCC/SSVC/refs/heads/main/data/json/ssvc_object_registry.json"); - const registry = await response.json(); - if (registry.types && registry.types.DecisionPoint && - registry.types.DecisionPoint.namespaces) { - const namespaces = registry.types.DecisionPoint.namespaces; - for (const nsKey in namespaces) { - const namespace = namespaces[nsKey]; - if (namespace.keys) { - for (const key in namespace.keys) { - const keyEntry = namespace.keys[key]; - if (keyEntry.versions) { - for (const version in keyEntry.versions) { - const versionEntry = keyEntry.versions[version]; - if (versionEntry.obj && versionEntry.values) { - let mdata = {data: versionEntry.obj}; - SSVC.decision_points.push(mdata); - } - } - } + +function createSSVC(csv, uploaded) { + const exporter = { "ssvcV1_0_1": { + "id": "CVE-1999-1234", + "selections": [], + "timestamp": (new Date()).toISOString(), + "schemaVersion": "1-0-1" + }}; + const ssvcTable = []; + let jsonTree = {} + let CSV = ""; + let outcomeTitle; + let lines = []; + let headers = []; + let dset = []; + if(typeof(csv) === "object") { + /* This is JSON data more powerful use it */ + jsonTree = simpleCopy(csv); + if(('schemaVersion' in jsonTree) && + (jsonTree.schemaVersion === '2.0.0') && + ('decision_points' in jsonTree)) { + if(('outcome' in jsonTree) && + (jsonTree.outcome in jsonTree.decision_points)) + outcomeTitle = jsonTree.decision_points[jsonTree.outcome].name; + let hkeys = []; + dpMap = {}; + let outcomeset = []; + Object.entries(jsonTree.decision_points).forEach(function([k,dp]) { + /* Dynamically build the name map per Tree. Assumption is there + are NO two decision points with the same name */ + if(dp.name in dpMap) + topalert("danger", "Duplicate Names found in Decision Table can cause confusion", 0); + dpMap[dp.name] = {name: dp.name, version: dp.version, + namespace: dp.namespace, data: dp}; + if(k != jsonTree.outcome) { + dset.push(dp.values.map(x => x.name)); + headers.push(dp.name); + hkeys.push(k); + } else { + /* Make sure the dset has the last entry as outcome*/ + outcomeset = dp.values.map(x => x.name); } - } + }); + dset.push(outcomeset); + headers.push(outcomeTitle); + hkeys.push(jsonTree.outcome); + if('mapping' in jsonTree) + jsonTree.mapping.forEach(function(dvpair) { + const line = hkeys.map(function(k) { + const vk = dvpair[k]; + const dp = jsonTree.decision_points[k]; + for(let i = 0; i < dp.values.length; i++) + if(dp.values[i].key == vk) + return dp.values[i].name; + }); + lines.push(line); + }); + } + } else { + lines = csv.split('\n'); + headers = lines.shift().split(','); + if(headers[0] == "row") { + /* CSV with row numbering setup so remove the first element*/ + headers.shift(); } } - if (registry.types && registry.types.DecisionTable && - registry.types.DecisionTable.namespaces) { - const namespaces = registry.types.DecisionTable.namespaces; - for (const nsKey in namespaces) { - const namespace = namespaces[nsKey]; - if (namespace.keys) { - for (const key in namespace.keys) { - const keyEntry = namespace.keys[key]; - if (keyEntry.versions) { - for (const version in keyEntry.versions) { - const versionEntry = keyEntry.versions[version]; - if (versionEntry.obj && versionEntry.obj.decision_points) { - let mdata = {data: versionEntry.obj, displayname: name_version(versionEntry.obj)}; - if(versionEntry.obj.name.indexOf("Deployer") > -1) - mdata['selected'] = true; - SSVC.decision_trees.push(mdata); - } - } - } + const main = document.createElement("main"); + function destroytip() { + let div = form.querySelector("[data-temp]"); + if(div) + div.remove(); + } + function tooltip(event, info) { + let div = form.querySelector("[data-temp]"); + if(!div) { + div = document.createElement("div"); + div.setAttribute("data-temp",1); + } + div.innerText = info; + const style = { + "display": "block", + "backgroundColor": "#333", + "opacity": "0.9", + "maxWidth": "300px", + "color": "white", + "borderRadius": "8px", + "position": "absolute", + "left": String(event.pageX + 10) + "px", + "top": String(event.pageY + 10) + "px", + "padding": "4px", + "border": "2px solid aqua" + }; + Object.assign(div.style,style); + form.appendChild(div); + } + function helptip(event) { + let dp = {}; + /* Check for Decision Point or Outcome and return helptip */ + const isdp = ["data-dp","data-outcomename"].some(function(fdp) { + if(event.target.hasAttribute(fdp)) { + /* A Decision Point help tip */ + dp = get_decision_point(event.target.getAttribute(fdp)); + if(dp.definition) { + tooltip(event, dp.definition); + return true; } } - } - } - SSVC.decision_points.sort(dtreeSort); - load_trees(); -} - -function deepSet(form, obj, path) { - if(!path) - path = ""; - for (const key in obj) { - if (typeof obj[key] === "object") { - deepSet(form, obj[key], path ? path + "-" + key : key); - } else { - const fullpath = path ? path + "-" + key : key; - const input = form.elements.namedItem("obj-" + fullpath); - if(input) { - input.value = obj[key]; - input.defaultValue = obj[key]; - if(input.onchange) - input.onchange(input); + /* This is more like continue */ + return false; + }); + if(isdp) + return false; + /* A Decision Point value helptip */ + const dpInput = event.target.querySelector("input"); + if(dpInput) { + if(dpInput.parentElement.parentElement.getAttribute("data-help")) { + dp = JSON.parse(dpInput.parentElement.parentElement.getAttribute("data-help")); } else { - console.log("Unassigned value ", key, fullpath, obj[key]); + dp = get_decision_point(dpInput.name); + if(dp.definition) + dpInput.parentElement.parentElement.setAttribute("data-help",JSON.stringify(dp)); + } + } + if(dp.values) { + for(let i=0; i options.length - 1) { - /* Add any new Decision Points that were imported or added */ - for(let i=options.length - 1; i < SSVC.decision_points.length; i++) { - const obj = SSVC.decision_points[i]; - const info = obj.data.namespace + "/" + name_version(obj.data); - const opt = new Option(info, JSON.stringify(obj.data)); - dpSelect.appendChild(opt); - } - options = dpSelect.querySelectorAll("option"); - } + if(uploaded) { + /*Create Custom Decision Points and add them to popup */ + const newdps = Object.keys(ssvcTable[0]).reduce(function(ac,name) { + if(name != outcomeTitle) { + let version = "1.0.0"; + let namespace = "demo/custom" + ac[name] = {"filename": "memory:" + name , + "data": {"namespace": namespace, + "name": name, + "version": version, + "definition": name, + "schemaVersion": "1-0-1", + "values": [] + } + } + } + return ac; + }, {}); + ssvcTable.forEach(function(row) { + Object.keys(row).forEach(function(dpName) { + const value = row[dpName]; + if(newdps[dpName]) { + if(newdps[dpName].data.values.findIndex(function(nvalue) { + return nvalue.name == value;}) < 0) { + newdps[dpName].data.values.push({"name": value, "definition": value, "key": value[0]}); + } + } - if(w.parentElement.hasAttribute("data-outcomeName")) { - dpSelect.setAttribute("data-outcomeName", - w.parentElement.getAttribute("data-outcomeName")); - rpopUp.querySelector("h4").innerHTML = "Customize Outcome"; - - } else if(w.hasAttribute("data-adddp")) { - dpSelect.removeAttribute("data-outcomeName"); - /* This is a new Decision Point so Add Decision Point is the action */ - rpopUp.querySelector("h4").innerHTML = "Add Decision Point"; - rpopUp.querySelector("[data-update]").innerText = "Add"; - } else { - dpSelect.removeAttribute("data-outcomeName"); - rpopUp.querySelector("h4").innerHTML = "Customize Decision Point"; - rpopUp.querySelector("[data-update]").innerText = "Update"; - dpName = w.parentElement.getAttribute("data-dp"); - dpIndex = w.parentElement.getAttribute("data-dpIndex"); - const selectdp = get_decision_point(dpName); - if(selectdp.name) { - dpSelect.setAttribute("data-selectdp", JSON.stringify(selectdp)); - const i = SSVC.decision_points.findIndex(function(dp) { - return match_name_ns_vers(dp,selectdp); }); - if (i > -1) { - dpSelect.options.selectedIndex = i + 1; - dpSelect.dispatchEvent(new Event("change")); - } - } else { - /* This decision point is unknown to us */ - dpSelect.removeAttribute("data-selectdp"); - clear_popup_form(dpSelect, rpopUp); - } + }); + /*Append new decision points */ + decision_points.push.apply(decision_points, + Object.values(newdps)); } - dpForm.setAttribute("data-dpIndex", dpIndex); - dpForm.setAttribute("data-dp", dpName); - disable_current_dps(options); -} -function toggleAll(doselect) { - const main = SSVC.form.querySelector('main'); - if (arguments.length < 1) { - const selected = main.querySelectorAll('input[type="checkbox"]:not(:checked)').length; - if (selected) - doselect = true; + decision_table = ssvcTable; + const numberTable = toNumberTable(decision_table,Object.keys(decision_table[0])); + const features = []; + const results = [] + numberTable.forEach(function(row) { + const outcome = row.pop(); + if(results[outcome]) + results[outcome] = results[outcome] + 1; else - doselect = false; - } - let tempel; - main.querySelectorAll("input[type='checkbox']").forEach(function(el) { - el.checked = doselect; - tempel = el; + results[outcome] = 1; + results.push(outcome); + features.push(row); }); - main.dispatchEvent(new Event('change')); - /* Put full tree back like it was */ - try { - const jsonData = document.querySelector("[data-tab='JSON']").innerText; - const jsonTree = JSON.parse(jsonData); - graphModule.dt_graph(jsonTree); - } catch(err) { - console.log("Reset form error " + err); - } -} -function selectCustom(name, datatree, fIndex) { - let clbutton = SSVC.form.parentElement.querySelector("[data-clear]"); - clbutton.setAttribute("data-json", JSON.stringify(datatree, null, 2)); - const sample = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - if(sample.querySelector("[selected]")) - sample.querySelector("[selected]").removeAttribute("selected"); - if(fIndex < 0) { - const opt = new Option(name, String(fIndex * -1), false, true); - if(name) { - opt.text = "[Private] " + name - opt.selected = true; - opt.setAttribute("data-customdt",1); - } - sample.appendChild(opt); - } else { - sample.querySelectorAll("option").forEach(function(option) { - if(option.textContent == name) - option.value = fIndex; + if(Object.keys(results).length > 1) { + const labels = decision_table.map(function(x) { + return x[outcomeTitle]; }); - } - toggleAll(true); -} -function verify_update_mapping(inp, clbutton) { - let val = inp.value; - let jsonTree = JSON.parse(clbutton.getAttribute("data-json")); - if(jsonTree && jsonTree.mapping) { - let outcomedp = jsonTree.decision_points[jsonTree.outcome]; - let dpv = outcomedp.values.find(dpv => dpv.name == val); - if(!dpv) { - alert("The Outcome is not part of the planned Outcomes"); - return false; - } - let index = -1; - SSVC.form.querySelectorAll("input[data-initialvalue]") - .forEach(function(cinp,i) { - if(cinp == inp) - index = i; - }); - if(index < 0) { - alert("Unable to find matching row in SSVC.mapping"); - return false; + const featureImportance = computeFI(features,labels); + if(Object.keys(featureImportance).length == features[0].length) { + const pfdiv = document.createElement("div"); + pfdiv.style.display = "table-row"; + for(let i=0; i < features[0].length; i++) { + const fdiv = document.createElement("div"); + fdiv.innerText = featureImportance[i]['importance'].toFixed(4); + fdiv.style.display = "table-cell"; + fdiv.style.border = "1px solid cyan"; + pfdiv.appendChild(fdiv); + } + const fdiv = document.createElement("div"); + fdiv.innerText = "<= Feature Importance"; + pfdiv.appendChild(fdiv); + allrows.prepend(pfdiv); } - jsonTree.mapping[index][jsonTree.outcome] = dpv.key; - clbutton.setAttribute("data-json",JSON.stringify(jsonTree)); - return true; } else { - alert("Unable to update new Outcome"); - return false; + console.log("There are no features to select importance from"); } -} -function customize(w) { - const clbutton = SSVC.form.parentElement.querySelector("[data-clear]"); - if(w.innerHTML == "Customize") { - clbutton.removeAttribute("data-changed"); - topalert("Edit, Remove or Add Decision Points, update Outcomes to create a new Decision Model and save it as a Decision Tree","success",0); - toggleAll(true); - w.innerHTML = "Save Changes"; - lock_unlock(true); - SSVC.form.querySelectorAll("input[type='checkbox']").forEach(function(checkbox) { - checkbox.disabled = true; - checkbox.nextSibling.style.opacity = 0.5; - }); - const divOutcome = SSVC.form.querySelector("[data-outcomeName]"); - const span = document.createElement("span"); - span.innerHTML = "✎"; - span.style.color = "#007bff"; - span.addEventListener("click",function() { - popupEditDP(this); - }); - divOutcome.appendChild(span); - const alldps = SSVC.form.querySelectorAll("[data-dp]"); - /* There are two displays of each DP*/ - const dplength = alldps.length/2; - alldps.forEach(function(el, i) { - if(el.querySelector("span")) - return; - const span = document.createElement("span"); - span.innerHTML = "✎"; - span.style.color = "#007bff"; - span.title = "Edit Decision Point"; - span.addEventListener("click",function() { - popupEditDP(this); - }); - const delspan = document.createElement("span"); - delspan.title = "Delete Decision Point"; - delspan.innerHTML = "⊖"; - delspan.addEventListener("click", function(ev) { - deleteDP(this); + allrows.prepend(rowDiv); + allrows.style.display = "table"; + allrows.setAttribute("data-tab","table"); + form.appendChild(main); + form.appendChild(h5button("SSVC Table", "current", "table")); + form.appendChild (document.createTextNode (" ")); + form.appendChild(h5button("JSON", null, "JSON")); + form.appendChild (document.createTextNode (" ")); + form.appendChild(h5button("CSV", null, "CSV")); + form.appendChild (document.createTextNode (" ")); + form.appendChild(h5button("Graph", null, "GRAPH")); + const btn = form.parentElement.querySelector("[data-clear]"); + btn.style.backgroundColor = "#dc3545"; + btn.style.color = "white"; + btn.innerText = " CLEAR "; + btn.type = "button"; + if(typeof(csv) == "object") + btn.setAttribute("data-json", JSON.stringify(csv,null,2)); + else + btn.setAttribute("data-csv", csv); + btn.addEventListener("click",clear); + form.appendChild(allrows); + const code = document.createElement("code"); + code.style.display = "none"; + code.style.border = "1px solid gray"; + code.style.width = "fit-content" + code.style.backgroundColor = "#eee"; + code.style.padding = "6px"; + code.style.whiteSpace = "pre-wrap"; + code.style.maxWidth = "90%"; + code.setAttribute("data-tab","JSON"); + code.innerText = JSON.stringify(jsonTree, null, 4); + form.appendChild(code); + const tcode = code.cloneNode(); + tcode.setAttribute("data-tab","CSV"); + tcode.innerText = CSV; + tcode.dataset.csv = CSV; + form.appendChild(tcode); + const tgraph = document.createElement("div"); + tgraph.id = "graph" + tgraph.setAttribute("data-tab","GRAPH"); + tgraph.style.display = "none"; + tgraph.innerText = "Graph not available for CSV data"; + form.appendChild(tgraph); + if(jsonTree.decision_points) + graphModule.dt_graph(csv); + function filterData(ev) { + exporter.ssvcV1_0_1.selections = []; + if(main.querySelectorAll("input:checked").length == 0) { + form.querySelectorAll('[data-row]').forEach(function(row) { + row.style.display="none"; }); - delspan.style.color = "red"; - el.appendChild(span); - if(!((i == dplength -1) || (i == dplength*2 -1))) - el.appendChild(delspan); - el.setAttribute("TM",String(i) + "- " + String(dplength)); - if((i == dplength - 2) || (i == dplength*2 - 2)) { - const addspan = document.createElement("span"); - addspan.innerHTML = "⊕"; - addspan.style.color = "#28a745"; - addspan.setAttribute("data-adddp",1); - addspan.addEventListener("click", function(ev) { - popupEditDP(this); + return update_stats(); + } + const div = ev.target.parentElement; + const ldivs = Array.from(form.querySelectorAll("main > div")); + ldivs.pop(); + ldivs.forEach(function(div) { + div.style.opacity = 1.0; + }); + if(div && div.hasAttribute("data-result")) { + const results = div.parentElement.querySelectorAll("input:checked"); + main.querySelectorAll("input").forEach(inp => inp.checked= false); + if(results.length == 0) { + form.querySelectorAll('[data-row]').forEach(function(row) { + row.style.display="none"; }); - el.appendChild(addspan); + return update_stats(); } - }); - SSVC.form.querySelectorAll("[data-outcome]").forEach(function(el) { - const inp = document.createElement("input"); - inp.value = el.innerText; - inp.dataset.initialvalue = el.innerText; - inp.addEventListener('change', function(e) { - const inp = e.target; - inp.style.border = "1px solid grey"; - if(!inp.value) - return alert("Outcome cannot be empty!"); - if (inp.value !== inp.dataset.initialValue) { - if(verify_update_mapping(inp,clbutton)) { - clbutton.setAttribute("data-changed", "1"); - } else { - inp.style.border = "2px solid red"; - inp.focus(); + /* This is clicking on outcome be wary */ + topalert("When filtering by Outcome the Decision Point values can look confounded!","warn",4); + ldivs.forEach(function(div) { + div.style.opacity = 0.6; + }); + let counter = 0; + ssvcTable.forEach(function(mrow,i) { + let row = simpleCopy(mrow); + let drows = form.querySelectorAll("[data-row]"); + drows[i].style.display = "none"; + results.forEach(function(result) { + result.checked = true; + result.parentElement.style.opacity = 1.0; + if(row[result.name] == result.value) { + counter++; + drows[i].style.display = "table-row"; + delete row[result.name]; + Object.entries(row).forEach(function([dpname,dpvalue]) { + let sel = 'input[name="'+dpname + + '"][value="'+dpvalue+'"]'; + let inp = form.querySelector(sel); + if(inp) + inp.checked = true; + }); } - } + }); }); - el.innerText = ""; - el.appendChild(inp); - }); - } else { - /* new Decision Tree Setup */ - if(!clbutton.hasAttribute("data-changed")) { - return alert("Nothing has changed or error field not fixed!"); - } - let jsonTree = {}; - if(clbutton.hasAttribute("data-json")) { - jsonTree = JSON.parse(clbutton.getAttribute("data-json")); + const h5 = form.querySelector("h5"); + let text = String(counter) + " of " + String(ssvcTable.length) + h5.innerText = "-- SSVC Table (selected " + text + ") -- "; + return update_stats(); } - /* Do we need to update mapping?*/ - const sample = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - const nextel = sample.nextElementSibling; - let current = sample[sample.selectedIndex].innerText - if(nextel.tagName.toUpperCase() == "DIV") { - nextel.querySelectorAll("input").forEach(function(inp) { - if(!inp.value) - jsonTree["error"] = "Value for " + niceString(inp.name) - + " CANNOT be empty!"; - jsonTree[inp.name] = inp.value; - }); + if(ev.target && ev.target.tagName.toUpperCase() == "INPUT" + && ev.target.type.toLowerCase() == "checkbox") { + graphModule.graph_dynamic(ev.target); } - if(jsonTree.error) - return alert(jsonTree.error); - if(!validate_namespace(jsonTree.namespace)) - return; - w.innerHTML = "Customize"; - lock_unlock(false); - SSVC.form.querySelectorAll("input[type='checkbox']").forEach(function(checkbox) { - checkbox.disabled = false; - checkbox.nextSibling.style.opacity = 1.0; - }); - /* Update JSON Tree Mapping */ - SSVC.form.querySelectorAll("[data-dp]").forEach(function(el) { - if(el.querySelector("span")) - el.querySelector("span").remove(); + main.querySelectorAll("[data-result]").forEach(function(result) { + result.style.fontWeight = "normal"; + result.style.opacity = "0.6"; + const inp = result.querySelector("input"); + if(inp) + inp.checked = false; }); - SSVC.form.innerHTML = ""; - createSSVC(jsonTree, false); - /* Find if this is already a custom built tree and - update it if needed */ - let findex = SSVC.decision_trees.findIndex(function(dt) { - if(dt.custom) - return dt.displayname == current; - else - current = name_version(jsonTree); + const selections = {}; + main.querySelectorAll("input:checked").forEach(function(input) { + const div = input.parentElement; + /*Ignoore outcome checkboxes that are checked */ + if(div && div.hasAttribute("data-result")) + return; + if(input.name in selections) + selections[input.name].push(input.value); + else + selections[input.name] = [input.value]; }); - - topalert("Latest values have been saved locally!","success",3); - if(findex > -1) { - SSVC.decision_trees[findex]["data"] = jsonTree; - } else { - /* Now findex will basicaly represent the last element - in the SSVC.decision_trees */ - findex = -1 * SSVC.decision_trees.length; - SSVC.decision_trees.push({data: jsonTree, displayname: current, custom: 1}); - } - selectCustom(current, jsonTree, findex); - let custom_ssvc = {}; - ["decision_trees","decision_points"].forEach(function(dtype) { - custom_ssvc[dtype] = []; - SSVC[dtype].forEach(function(dtdp) { - if(dtdp.custom) - custom_ssvc[dtype].push(dtdp); + let rows = ssvcTable; + Object.keys(selections).forEach(function(decision_point) { + const dp = get_decision_point(decision_point); + exporter.ssvcV1_0_1.selections.push({"namespace": dp.namespace || "ssvc", + "version": dp.version || "1.0.0", + "values": selections[decision_point], + "name": decision_point}); + let chosen = selections[decision_point]; + rows = rows.filter(function(row) { + if(chosen.includes(row[decision_point])){ + if(outcomeTitle in row) { + return row; + } + } }); - }) - localStorage.setItem("custom_ssvc", JSON.stringify(custom_ssvc)); - SSVC.form.parentElement.querySelector("[data-session]").style.display = "block"; - } -} -function load_trees() { - const sampletrees = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - sampletrees.innerHTML = ""; - const displaySet = {}; - SSVC.decision_trees.forEach(function(decision_tree, i) { - const opt = new Option(decision_tree.displayname, i , decision_tree.selected, decision_tree.selected); - if(decision_tree.custom) { - opt.setAttribute("data-customdt","1"); - opt.innerText = "[Private] " +opt.innerText - } - if(displaySet[opt.innerText]) - opt.innerText = add_dash_n(opt.innerText, displaySet); - sampletrees.appendChild(opt); - if(decision_tree.selected) - loadSSVC(String(i)); - displaySet[opt.innerText] = 1; - }); - sampletrees.appendChild(new Option("Upload CSV/JSON","upload_file")); -} -async function delete_session() { - if(await popupConfirm("Are you sure, you want to delete all custom Decision Trees?") == "Yes") { - localStorage.removeItem("custom_ssvc"); - for (let i = 0; i < SSVC.decision_trees.length; i++) { - if(SSVC.decision_trees[i].custom) { - SSVC.decision_trees.splice(i, 1); - i--; - } - } - topalert("All custom decision trees have been removed", "warn"); - load_trees(); - SSVC.form.parentElement.querySelector("[data-session]").style.display = "none"; - } else { - topalert("Good! Custom decision trees have been retained!", "success", 3); - } -} -async function delete_dtree() { - const sampletrees = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - const delete_tree = sampletrees.options[sampletrees.selectedIndex].innerText; - const opt = sampletrees.options[sampletrees.selectedIndex]; - if(!opt.hasAttribute("data-customdt")) { - return alert("The default trees cannot be deleted"); - } - if(await popupConfirm("Are you sure, you want to delete custom Decision Tree \""+ delete_tree + "\"?") == "Yes") { - let old_tree = simpleCopy(SSVC.decision_tree[parseInt(opt.value)]); - SSVC.decision_tree.splice(parseInt(opt.value), 1); - sampletrees.options[sampletrees.selectedIndex].remove(); - sampletrees.dispatchEvent(new Event("change")); - const saved = JSON.parse(localStorage.getItem("custom_ssvc")); - let savedIndex = saved.decision_trees.findIndex(function(dt) { - return match_name_ns_vers(dt,old_tree.data); }); - if(savedIndex > -1) - saved.decision_trees.splice(savedIndex,1); - localStorage.setItem("custom_ssvc", JSON.stringify(saved)); - } else { - topalert("Good! Nothing was deleted!", "success", 3); - } -} -function rename_dtree() { - const sampletrees = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - const opt = sampletrees.options[sampletrees.selectedIndex]; - if(!opt.hasAttribute("data-customdt")) { - alert("The default trees cannot be deleted"); - return; - } - const old_index = parseInt(sampletrees.options[sampletrees.selectedIndex].value); - if(SSVC.decision_trees[old_index] && SSVC.decision_trees[old_index].data) { - const old_tree = SSVC.decision_trees[old_index]; - const old_name = old_tree.data.name; - const new_name = prompt("Enter new name for the current decision tree \"" + old_name + "\":"); - SSVC.decision_trees[old_index].data.name = new_name; - opt.innerText = name_version(SSVC.decision_trees[old_index].data); - SSVC.decision_trees[old_index].displayname = opt.innerText; - const saved = JSON.parse(localStorage.getItem("custom_ssvc")); - let savedIndex = saved.decision_trees.findIndex(function(dt) { - return match_name_ns_vers(dt,old_tree.data); + form.querySelectorAll("[data-row]").forEach(function(trow) { + trow.style.display = "none"; }); - if(savedIndex > -1) - saved.decision_trees[savedIndex] = SSVC.decision_trees[old_index]; - localStorage.setItem("custom_ssvc", JSON.stringify(saved)); - } -} -function download_ssvc_csv() { - download_ssvc('csv'); -} -function download_ssvc_json() { - download_ssvc('json'); -} -function download_ssvc(dtype) { - const btn = SSVC.form.parentElement.querySelector("[data-download-" + dtype + "]"); - btn.click(); -} -function restore_session() { - if(localStorage.getItem("custom_ssvc")) { - const saved = JSON.parse(localStorage.getItem("custom_ssvc")); - delete saved.form; - ["decision_points","decision_trees"].forEach(function(item) { - console.log(saved[item]); - SSVC[item].push.apply(SSVC[item],saved[item]); + rows.forEach(function(row) { + form.querySelectorAll("[data-row]").forEach(function(trow) { + let crow = JSON.parse(trow.getAttribute("data-row")); + if(compareObj(crow,row)) + trow.style.display = "table-row"; + }); + const rowTitle = row[outcomeTitle].replaceAll('"','\\"'); + main.querySelectorAll('[data-result="'+rowTitle+'"]').forEach(function(result) { + result.style.fontWeight = "bolder"; + result.style.opacity = "1.0"; + const inp = result.querySelector("input"); + if(inp) + inp.checked = true; + }); }); - load_trees(); - topalert("Session variables have been restored!","success",3); - } else { - topalert("No previous session has been found to restore!","danger"); + const h5 = form.querySelector("h5"); + let text = String(rows.length) + " of " + String(ssvcTable.length) + h5.innerText = "-- SSVC Table (selected " + text + ") -- "; + exporter.ssvcV1_0_1.timestamp = (new Date()).toISOString(); + /* always display JSON Tree + code.innerHTML = JSON.stringify(exporter, null, 4); + */ + update_stats(); } + main.addEventListener('change', filterData); + update_stats(); } -document.addEventListener("DOMContentLoaded", function () { - console.log("Dom content loaded"); - SSVC.form = document.getElementById('ssvcForm'); - get_decision_points(); - if(localStorage.getItem("custom_ssvc")) { - topalert("You have some custom Decision Trees saved from earlier session. " + - "use \"Restore Session\" under \"Custom Trees\" to restore & manage these", - "success",0); - SSVC.form.parentElement.querySelector("[data-session]").style.display = "block"; - } -}); +function calculateEntropy(decision_table, targetCol) { + const valueCounts = {}; + decision_table.forEach(row => { + const value = row[targetCol]; + valueCounts[value] = (valueCounts[value] || 0) + 1; + }); -function dpValueClone(el) { - const pDiv = el.parentElement.parentElement; - pDiv.querySelectorAll("span").forEach(function(x) { x.remove(); }); - const count = pDiv.querySelectorAll("[data-clone]").length/2 - 1; - const delspan = document.createElement("span"); - delspan.innerHTML = "⊖"; - delspan.addEventListener("click", function(ev) { - const el = this; - el.parentElement.parentElement.nextSibling.remove(); - el.parentElement.parentElement.remove(); - }); - delspan.style.color = "red"; - [el.parentElement.nextElementSibling, - el.parentElement.nextElementSibling.nextElementSibling].forEach(function(row,i) { - const nrow = row.cloneNode(true); - const nel = nrow.querySelector("input,textarea"); - nel.value = ""; - if(nel.onchange) - nel.onchange(nel); - nel.name = nel.name.replace(/(\d+)([^\d]*)$/, function(_,n,g) { - return String(count + 1)+g - }); - nrow.setAttribute("data-temp","1"); - if (i == 0) - nrow.children[0].prepend(delspan); - pDiv.appendChild(nrow); - }); + const totalCount = decision_table.length; + let entropy = 0; + for (const count of Object.values(valueCounts)) { + const p = count / totalCount; + entropy -= p * Math.log2(p); + } + return entropy; } -function textAreaAutoSize(element) { - element.style.height = "1px"; - element.style.height = String(4 + element.scrollHeight) + "px"; +function calculateInformationGain(decision_table,featureCol, targetCol) { + const totalEntropy = calculateEntropy(decision_table, targetCol); + const featureSet = new Set(decision_table.map(row => row[featureCol])); + const featureValues = Array.from(featureSet); + + let weightedEntropy = 0; + featureValues.forEach(value => { + const subset = decision_table.filter(row => row[featureCol] === value); + const subsetEntropy = calculateEntropy(subset, targetCol); + const subsetWeight = subset.length / decision_table.length; + weightedEntropy += subsetWeight * subsetEntropy; + }); + + return totalEntropy - weightedEntropy; } -function set_deep(obj,prop,val) { - /* For the Object obj set the property of a prop to val - recursively. example set_deep({a:{b:{c:{"good"}}}},"a-b-c","bad") - will return {a:{b:{c:{"bad"}}}} */ - if(typeof(obj) != "object") - return undefined; - let fobj = simpleCopy(obj); - var x = fobj; - let props = prop.split("-"); - let fprop = props.pop(); - for(var i=0; i x.data),"DT_", 2); - console.log(jsonTree); - createSSVC(jsonTree, false); - customize({innerHTML: "Customize"}); - clbutton.setAttribute("data-changed","1"); - topalert(); - topalert("New Decision Tree has Outcomes that are evenly laid out! Please update these " + - "as appropriate for your Decision Model, before Saving it!","warn",0); } -async function deleteDP(el) { - const dpName = el.parentElement.childNodes[0].textContent; - const confirm = await popupConfirm('Do you want to delete Decision Point "' + dpName + '"'); - if(confirm == "Yes") { - try { - const delDP = el.parentElement.getAttribute("data-dp"); - const alldps = Array.from(SSVC.form.querySelectorAll("main [data-dp]")).map(function(el) { return el.getAttribute("data-dp")}); - if(alldps.length < 3) { - topalert("Minimum two decision points are needed", "danger"); - return false; - } - const removedp = JSON.parse(el.parentElement.parentElement.getAttribute("data-help")); - console.log(removedp); - const clbutton = SSVC.form.parentElement.querySelector("[data-clear]"); - const jsonTree = JSON.parse(clbutton.getAttribute("data-json")); - const matched = Object.keys(jsonTree.decision_points).some(function(dpkey) { - const dp = jsonTree.decision_points[dpkey]; - if(match_name_ns_vers({data: dp},removedp)) { - delete jsonTree.decision_points[dpkey]; - return true; +async function get_decision_points() { + /* Use the URL registry = await response.json(); */ + const registry_url = "https://raw.githubusercontent.com/CERTCC/SSVC/refs/heads/main/data/json/ssvc_object_registry.json"; + const response = await fetch(registry_url); + const registry = await response.json(); + if (registry.types && registry.types.DecisionPoint && + registry.types.DecisionPoint.namespaces) { + const namespaces = registry.types.DecisionPoint.namespaces; + for (const nsKey in namespaces) { + const namespace = namespaces[nsKey]; + if (namespace.keys) { + for (const key in namespace.keys) { + const keyEntry = namespace.keys[key]; + if (keyEntry.versions) { + for (const version in keyEntry.versions) { + const versionEntry = keyEntry.versions[version]; + if (versionEntry.obj && versionEntry.values) { + let mdata = {data: versionEntry.obj}; + decision_points.push(mdata); + } + } + } } - return false; - }); - if(matched) - makeTree(jsonTree); - else - throw "Could not delete decision point"; - } catch(err) { - topalert(err,"danger"); + } } } + if (registry.types && registry.types.DecisionTable && + registry.types.DecisionTable.namespaces) { + const namespaces = registry.types.DecisionTable.namespaces; + for (const nsKey in namespaces) { + const namespace = namespaces[nsKey]; + if (namespace.keys) { + for (const key in namespace.keys) { + const keyEntry = namespace.keys[key]; + if (keyEntry.versions) { + for (const version in keyEntry.versions) { + const versionEntry = keyEntry.versions[version]; + if (versionEntry.obj && versionEntry.obj.decision_points) { + let mdata = {data: versionEntry.obj, displayname: name_version(versionEntry.obj)}; + if(versionEntry.obj.name.indexOf("Deployer") > -1) + mdata['selected'] = true; + decision_trees.push(mdata); + } + } + } + } + } + } + } + decision_points.sort(dtreeSort); + load_trees(); } -function find_key(dp,dt) { - /* Find a decision points' key attribute in a decision tree*/ - if('decision_points' in dt) { - for (const [fkey, fdp] of Object.entries(dt.decision_points)) { - if(['name','namespace','version'].every(function(prop) { - return prop in fdp && prop in dp && dp[prop] == fdp[prop]; - })) - return fkey; + +function deepSet(form, obj, path) { + if(!path) + path = ""; + for (const key in obj) { + if (typeof obj[key] === "object") { + deepSet(form, obj[key], path ? path + "-" + key : key); + } else { + const fullpath = path ? path + "-" + key : key; + const input = form.elements.namedItem("obj-" + fullpath); + if(input) { + input.value = obj[key]; + input.defaultValue = obj[key]; + if(input.onchange) + input.onchange(input); + } else { + console.log("Unassigned value ", key, fullpath, obj[key]); + } } } - return; } -function uniq_key(obj, arr, prefix, copyLength) { - if(!prefix) - prefix = ""; - if(copyLength && String(copyLength).match(/^[0-9]$/)) { - copyLength = parseInt(copyLength); - } else { - copyLength = 1; - } - let base = obj.name.normalize("NFD") - .replace(/[\u0300-\u036f]/g, "") - .replace(/[^a-zA-Z0-9_]/g, "") - .toUpperCase(); - - if (copyLength && copyLength > 0) { - base = base.substring(0, copyLength); - } - - if (!base[0] || !/[A-Z0-9]/.test(base[0])) { - base = "A" + base; - } - - if (base.length === 0) { - base = "A"; - } - - let xkey = prefix + base; - let counter = 0; - - while (arr.findIndex(xdp => xdp.key === xkey) > -1) { - counter++; - xkey = prefix + base + "_" + counter; - } - - return xkey; +function match_name_ns_vers(obj,selectobj) { + const props = ["name", "namespace", "version"]; + return props.every(function(prop) { + return obj.data.hasOwnProperty(prop) && + selectobj.hasOwnProperty(prop) && + obj.data[prop] == selectobj[prop]; + }); } - -function validate_namespace(namespace) { - if(!namespace.toLowerCase().startsWith("x_")) { - /* Only thing allowed is translation */ - if(!namespace.match(/\/[a-z\-0-9]*\//i)) { - alert("Changed Decision Point or Tree Namespace cannot use reserved namespaces. Either use x_com.example#psirt format or a pure translation ssvc/de-DE/ is allowed."); - return false; +function prepare_form(vForm, vSelect, selectdp, preFill, vars) { + if(!vSelect.hasAttribute("detect-change")) + vSelect.addEventListener("change",function(ev) { + const el = ev.target; + if(!el.value) + return clear_popup_form(vSelect, vForm); + const obj = JSON.parse(el.value); + Object.keys(obj).forEach(function(key) { + vForm.querySelectorAll("[data-temp]").forEach(function(div) { + div.remove(); + }); + if(vars in obj) { + const drows = obj[vars].length * 2; + const crows = vForm.querySelectorAll("[data-clone]").length; + const diff = (drows - crows)/2; + for(let i=0; i < diff; i++) + vForm.querySelector("button").click(); + } + deepSet(vForm, obj); + }); + }); + vSelect.setAttribute("detect-change","1"); + preFill.forEach(function(obj) { + let info; + /* Drop down for decision points has more information*/ + if (obj.data.namespace && obj.data.name && obj.data.version) + info = obj.data.namespace + "/" + name_version(obj.data); + else + info = obj.data.name; + const opt = new Option(info, JSON.stringify(obj.data)); + if(selectdp.name && match_name_ns_vers(obj,selectdp)) { + opt.selected = true; + selectdp['obj'] = true; } + vSelect.appendChild(opt); + }); + if(selectdp.obj) { + vSelect.dispatchEvent(new Event("change")); } - return true; } -function enumerateCombinations(dtree) { - const decisionPoints = dtree.decision_points; - const outcomeKey = dtree.outcome; - - const relevantPoints = Object.entries(decisionPoints) - .filter(([key]) => key !== outcomeKey); - - const pointsWithValues = relevantPoints.map(([id, dp]) => ({ - id: id, - values: dp.values.map(v => v.key) - })); - - function cartesianProduct(index, current, result) { - if (index === pointsWithValues.length) { - current[outcomeKey] = "0"; - result.push(Object.assign({}, current)); - return; +function popupStart(selector) { + const popup = form.parentElement.parentElement.querySelector("[id='ssvcPopup']"); + form.style.opacity = "0.3"; + form.style.pointerEvents = "none"; + popup.style.display = "block"; + /* The matching div under popup to display and work with */ + let rpopup; + Array.from(popup.children).forEach(function(el) { + if(el.hasAttribute(selector)) { + el.style.display = "block"; + rpopup = el; + } else { + el.style.display = "none"; } + }); + return rpopup; +} +function popupEnd() { + const popUp = form.parentElement.parentElement.querySelector("[id='ssvcPopup']"); + form.style.opacity = "1.0"; + form.style.pointerEvents = "all"; + popUp.style.display = "none"; + return popUp; +} - const point = pointsWithValues[index]; - Array.from(point.values).forEach(function (value) { - current[point.id] = value; - cartesianProduct(index + 1, current, result); +async function popupConfirm(message) { + const rpopUp = popupStart("data-yesno"); + rpopUp.querySelector("h4").innerText = message; + return new Promise(function(success, fail ) { + rpopUp.querySelectorAll("button").forEach(function(el) { + el.onclick = function() { success(el.innerText); popupEnd();} }); - } - - const result = []; - cartesianProduct(0, {}, result); - - const outcomeValues = decisionPoints[outcomeKey].values.map(v => v.key); - const outcomeCount = outcomeValues.length; - /* Spread outcome evenly across the results array*/ - const m = result.length; - const n = outcomeValues.length; - const blockSize = Math.floor(m / n); - let remainder = m % n; - - let index = 0; - for (let i = 0; i < n; i++) { - let size = blockSize + (remainder > 0 ? 1 : 0); - remainder = Math.max(0, remainder - 1); - for (let j = 0; j < size; j++) { - result[index][outcomeKey] = outcomeValues[i]; - index++; - } - } - return result; + }); +} +function clear_popup_form(iSelect, rpopUp) { + iSelect.selectedIndex = 0; + rpopUp.querySelectorAll("[data-temp]").forEach(function(el) { + el.remove(); + }); + rpopUp.querySelectorAll("input,textarea").forEach(function(input) { + input.value=""; + }); } +function disable_current_dps(options) { + /* Disable already used DPs */ + const current_dps = []; + form.querySelector("main").querySelectorAll("[data-dp]").forEach(function(el) { + try { + const dp = get_decision_point(el.getAttribute("data-dp")); + current_dps.push(dp); + } catch(err) { + console.log("Error while trying to detect current Decision Points " + err); + } + }); + options.forEach(function(option) { + if(option.value && (!option.selected)) { + try { + const odp = JSON.parse(option.value); + current_dps.forEach(function(cdp) { + if(match_name_ns_vers({"data": odp},cdp)) + option.setAttribute("disabled",1); + }); + } catch(err) { + console.log("Error while trying to match Decision Points to current options" + err); + } + } + }); +} -function updateTree() { - const clbutton = SSVC.form.parentElement.querySelector("[data-clear]"); - clbutton.removeAttribute("data-changed") - let jsonTree = {}; - if(clbutton.hasAttribute("data-json")) { - jsonTree = JSON.parse(clbutton.getAttribute("data-json")); - } - const popUp = SSVC.form.parentElement.parentElement.querySelector("[id='ssvcPopup']"); - const updatebtn = popUp.querySelector("[data-update]"); - const dpForm = popUp.querySelector("[data-customdp]") - .querySelector("form"); +function popupEditDP(w) { + topalert(); + const rpopUp = popupStart("data-customdp"); + const dpForm = rpopUp.querySelector("form"); const dpSelect = dpForm.querySelector("select"); - const dpOutcome = dpSelect.getAttribute("data-outcomeName"); - let changed = false; - const inputs = dpForm.querySelectorAll("input,textarea"); - let dp = deepGet(inputs); - for(let i=0; i options.length - 1) { + /* Add any new Decision Points that were imported or added */ + for(let i=options.length - 1; i < decision_points.length; i++) { + const obj = decision_points[i]; + const info = obj.data.namespace + "/" + name_version(obj.data); + const opt = new Option(info, JSON.stringify(obj.data)); + dpSelect.appendChild(opt); } - if(inputs[i].defaultValue && inputs[i].defaultValue != inputs[i].value) { - changed = true; - break; + options = dpSelect.querySelectorAll("option"); + } + + if(w.parentElement.hasAttribute("data-outcomeName")) { + dpSelect.setAttribute("data-outcomeName", + w.parentElement.getAttribute("data-outcomeName")); + rpopUp.querySelector("h4").innerHTML = "Customize Outcome"; + + } else if(w.hasAttribute("data-adddp")) { + dpSelect.removeAttribute("data-outcomeName"); + /* This is a new Decision Point so Add Decision Point is the action */ + rpopUp.querySelector("h4").innerHTML = "Add Decision Point"; + rpopUp.querySelector("[data-update]").innerText = "Add"; + } else { + dpSelect.removeAttribute("data-outcomeName"); + rpopUp.querySelector("h4").innerHTML = "Customize Decision Point"; + rpopUp.querySelector("[data-update]").innerText = "Update"; + dpName = w.parentElement.getAttribute("data-dp"); + dpIndex = w.parentElement.getAttribute("data-dpIndex"); + const selectdp = get_decision_point(dpName); + if(selectdp.name) { + dpSelect.setAttribute("data-selectdp", JSON.stringify(selectdp)); + const i = decision_points.findIndex(function(dp) { + return match_name_ns_vers(dp,selectdp); + }); + if (i > -1) { + dpSelect.options.selectedIndex = i + 1; + dpSelect.dispatchEvent(new Event("change")); + } + } else { + /* This decision point is unknown to us */ + dpSelect.removeAttribute("data-selectdp"); + clear_popup_form(dpSelect, rpopUp); } } - let olddp = {}; - /* Get previous decision point so we can compare it to the current */ - if(dpSelect.hasAttribute("data-selectdp")) - olddp = JSON.parse(dpSelect - .getAttribute("data-selectdp")); - /*Check if this decision point is in our registry */ - let registered = SSVC.decision_points.some(function(x) { - if(match_name_ns_vers(x, dp)) { - dp = x.data; - return true; - } - }); - if(changed) { - /*Check if it is a translation. */ - if(!validate_namespace(dp.namespace)) { - return; - } - /* Add data to dpMap and decision_points of global SSVC data */ - SSVC.dpMap[dp.name] = {"namespace": dp.namespace, "version": dp.version}; - } else { - if(match_name_ns_vers({"data": dp}, olddp)) { - alert("Nothing has changed"); - return; - } + dpForm.setAttribute("data-dpIndex", dpIndex); + dpForm.setAttribute("data-dp", dpName); + disable_current_dps(options); +} +function toggleAll(doselect) { + const main = form.querySelector('main'); + if (arguments.length < 1) { + const selected = main.querySelectorAll('input[type="checkbox"]:not(:checked)').length; + if (selected) + doselect = true; + else + doselect = false; } - let dpvkeys = {} - /* Doube verify and make sure tke key uniqueness */ - dp.values.forEach(function(val,i) { - if(!dp.values[i].key) - dp.values[i].key = uniq_key(val, dp.values); - if(dp.values[i].key in dpvkeys) - dp.values[i].key = uniq_key(val, dp.values); - dpvkeys[dp.values[i].key] = 1; + let tempel; + main.querySelectorAll("input[type='checkbox']").forEach(function(el) { + el.checked = doselect; + tempel = el; }); - popupEnd(); - let oldKey = find_key(olddp,jsonTree); - if(!registered) { - /* Enforce unique keys for values*/ - dp.key = uniq_key(dp, SSVC.decision_points.map(x => x.data)); - const info = dp.namespace + "/" + name_version(dp); - let opt = Array.from(dpSelect.querySelectorAll("option")) - .filter(function(x) { - return x.innerText == info + main.dispatchEvent(new Event('change')); + /* Put full tree back like it was */ + try { + const jsonData = document.querySelector("[data-tab='JSON']").innerText; + const jsonTree = JSON.parse(jsonData); + graphModule.dt_graph(jsonTree); + } catch(err) { + console.log("Reset form error " + err); + } +} +function selectCustom(name, datatree, fIndex) { + let clbutton = form.parentElement.querySelector("[data-clear]"); + clbutton.setAttribute("data-json", JSON.stringify(datatree, null, 2)); + const sample = form.parentElement.querySelector("[id='sampletrees']"); + if(sample.querySelector("[selected]")) + sample.querySelector("[selected]").removeAttribute("selected"); + if(fIndex < 0) { + const opt = new Option(name, String(fIndex * -1), false, true); + if(name) { + opt.text = "[Private] " + name + opt.selected = true; + opt.setAttribute("data-customdt",1); + } + sample.appendChild(opt); + } else { + sample.querySelectorAll("option").forEach(function(option) { + if(option.textContent == name) + option.value = fIndex; + }); + } + toggleAll(true); +} +function verify_update_mapping(inp, clbutton) { + let val = inp.value; + let jsonTree = JSON.parse(clbutton.getAttribute("data-json")); + if(jsonTree && jsonTree.mapping) { + let outcomedp = jsonTree.decision_points[jsonTree.outcome]; + let dpv = outcomedp.values.find(dpv => dpv.name == val); + if(!dpv) { + alert("The Outcome is not part of the planned Outcomes"); + return false; + } + let index = -1; + form.querySelectorAll("input[data-initialvalue]") + .forEach(function(cinp,i) { + if(cinp == inp) + index = i; }); - if(opt.length) { - opt[0].value = JSON.stringify(dp); - } else { - opt = new Option(info, JSON.stringify(dp)); - dpSelect.appendChild(opt); + if(index < 0) { + alert("Unable to find matching row in mapping"); + return false; } - SSVC.decision_points.push({"filename": "memory:" + dp.namespace - + dp.name, "data": dp, custom: 1}); + jsonTree.mapping[index][jsonTree.outcome] = dpv.key; + clbutton.setAttribute("data-json",JSON.stringify(jsonTree)); + return true; + } else { + alert("Unable to update new Outcome"); + return false; } - if(oldKey) { - /* This is to replace a decision point */ - const oldvalues = simpleCopy(jsonTree.decision_points[oldKey].values); - delete jsonTree.decision_points[oldKey]; - let newKey = dp.namespace + ":" + dp.key + ":" + dp.version; - if(dp.namespace.indexOf("x_") > -1) - newKey = dp.namespace.substr(0,3) + ":" + dp.key + ":" + dp.version; - jsonTree.decision_points[newKey] = dp; - if(dpOutcome) { - jsonTree.outcome = newKey; - } - if (olddp.values && olddp.values.length == dp.values.length) { - /* Leave the Tree Outcomes as-is*/ - if(jsonTree.mapping.every(function(tmap,i) { - let fI = oldvalues.findIndex(value => value.key == tmap[oldKey]) - if(fI > -1) { - delete jsonTree.mapping[i][oldKey]; - tmap[newKey] = dp.values[fI].key; - return true; - } - return false; - })) { - console.log("success"); - SSVC.form.innerHTML = ""; - jsonTree.key = uniq_key(jsonTree, SSVC.decision_trees.map(x => x.data),"DT_", 2); - createSSVC(jsonTree, false); - customize({innerHTML: "Customize"}); - clbutton.setAttribute("data-changed","1") +} +function customize(w) { + const clbutton = form.parentElement.querySelector("[data-clear]"); + if(w.innerHTML == "Customize") { + clbutton.removeAttribute("data-changed"); + topalert("Edit, Remove or Add Decision Points, update Outcomes to create a new Decision Model and save it as a Decision Tree","success",0); + toggleAll(true); + w.innerHTML = "Save Changes"; + lock_unlock(true); + form.querySelectorAll("input[type='checkbox']").forEach(function(checkbox) { + checkbox.disabled = true; + checkbox.nextSibling.style.opacity = 0.5; + }); + const divOutcome = form.querySelector("[data-outcomeName]"); + const span = document.createElement("span"); + span.innerHTML = "✎"; + span.style.color = "#007bff"; + span.addEventListener("click",function() { + popupEditDP(this); + }); + divOutcome.appendChild(span); + const alldps = form.querySelectorAll("[data-dp]"); + /* There are two displays of each DP*/ + const dplength = alldps.length/2; + alldps.forEach(function(el, i) { + if(el.querySelector("span")) return; - } else { - console.log("Failed"); - console.log(jsonTree,dp); + const span = document.createElement("span"); + span.innerHTML = "✎"; + span.style.color = "#007bff"; + span.title = "Edit Decision Point"; + span.addEventListener("click",function() { + popupEditDP(this); + }); + const delspan = document.createElement("span"); + delspan.title = "Delete Decision Point"; + delspan.innerHTML = "⊖"; + delspan.addEventListener("click", function(ev) { + deleteDP(this); + }); + delspan.style.color = "red"; + el.appendChild(span); + if(!((i == dplength -1) || (i == dplength*2 -1))) + el.appendChild(delspan); + el.setAttribute("TM",String(i) + "- " + String(dplength)); + if((i == dplength - 2) || (i == dplength*2 - 2)) { + const addspan = document.createElement("span"); + addspan.innerHTML = "⊕"; + addspan.style.color = "#28a745"; + addspan.setAttribute("data-adddp",1); + addspan.addEventListener("click", function(ev) { + popupEditDP(this); + }); + el.appendChild(addspan); } - } - } else if(updatebtn.innerText == "Add") { - if(!dp.version) - dp.version = "1.0.0"; - const newKey = dp.namespace + ":" + dp.key + ":" + dp.version; - jsonTree.decision_points[newKey] = dp; + }); + form.querySelectorAll("[data-outcome]").forEach(function(el) { + const inp = document.createElement("input"); + inp.value = el.innerText; + inp.dataset.initialvalue = el.innerText; + inp.addEventListener('change', function(e) { + const inp = e.target; + inp.style.border = "1px solid grey"; + if(!inp.value) + return alert("Outcome cannot be empty!"); + if (inp.value !== inp.dataset.initialValue) { + if(verify_update_mapping(inp,clbutton)) { + clbutton.setAttribute("data-changed", "1"); + } else { + inp.style.border = "2px solid red"; + inp.focus(); + } + } + }); + el.innerText = ""; + el.appendChild(inp); + }); } else { - topalert("Error: Unable to find if this is a new Decision Point or a replacement", - "danger"); - } - /* Somethings have majorly changed, we have to update the decision tree mappings */ - makeTree(jsonTree); -} -function schemaTransform(dtnew) { - const dtobj = simpleCopy(dtnew); - const dtold = {}; - let outcomeName; - if('outcome' in dtobj) - outcomeName = dtobj.outcome; - if('decision_points' in dtobj) { - dtold['decision_points'] = []; - Object.entries(dtobj['decision_points']).forEach(function([k,dp]) { - dp.decision_type = "simple"; - if(k == outcomeName) - dp.decision_type = "final"; - dp.values.forEach(function(dv) { - dv.label = dv.name; - delete dv.name; + /* new Decision Tree Setup */ + if(!clbutton.hasAttribute("data-changed")) { + return alert("Nothing has changed or error field not fixed!"); + } + let jsonTree = {}; + if(clbutton.hasAttribute("data-json")) { + jsonTree = JSON.parse(clbutton.getAttribute("data-json")); + } + /* Do we need to update mapping?*/ + const sample = form.parentElement.querySelector("[id='sampletrees']"); + const nextel = sample.nextElementSibling; + let current = sample[sample.selectedIndex].innerText + if(nextel.tagName.toUpperCase() == "DIV") { + nextel.querySelectorAll("input").forEach(function(inp) { + if(!inp.value) + jsonTree["error"] = "Value for " + niceString(inp.name) + + " CANNOT be empty!"; + jsonTree[inp.name] = inp.value; }); - dp.options = dp.values; - delete dp.values; - dp.label = dp.name.replaceAll(",","|"); - delete dp.name; - dtold.decision_points.push(dp); + } + if(jsonTree.error) + return alert(jsonTree.error); + if(!validate_namespace(jsonTree.namespace)) + return; + w.innerHTML = "Customize"; + lock_unlock(false); + form.querySelectorAll("input[type='checkbox']").forEach(function(checkbox) { + checkbox.disabled = false; + checkbox.nextSibling.style.opacity = 1.0; }); - } - if('mapping' in dtobj) { - dtold['decisions_table'] = []; - dtobj.mapping.forEach(function(dvpair) { - const dt = {} - Object.entries(dvpair).forEach(function([k,v]) { - const dp = dtnew.decision_points[k]; - const name = dp.name.replaceAll(",","|"); - for(let i=0; i< dp.values.length; i++) { - if('key' in dp.values[i] && dp.values[i].key == v) - dt[name] = dp.values[i].name; - } - }); - dtold['decisions_table'].push(dt); + /* Update JSON Tree Mapping */ + form.querySelectorAll("[data-dp]").forEach(function(el) { + if(el.querySelector("span")) + el.querySelector("span").remove(); + }); + form.innerHTML = ""; + createSSVC(jsonTree, false); + /* Find if this is already a custom built tree and + update it if needed */ + let findex = decision_trees.findIndex(function(dt) { + if(dt.custom) + return dt.displayname == current; + else + current = name_version(jsonTree); }); + + topalert("Latest values have been saved locally!","success",3); + if(findex > -1) { + decision_trees[findex]["data"] = jsonTree; + } else { + /* Now findex will basicaly represent the last element + in the decision_trees */ + findex = -1 * decision_trees.length; + decision_trees.push({data: jsonTree, displayname: current, custom: 1}); + } + selectCustom(current, jsonTree, findex); + let custom_ssvc = {}; + ["decision_trees","decision_points"].forEach(function(dtype) { + custom_ssvc[dtype] = []; + SSVC[dtype].forEach(function(dtdp) { + if(dtdp.custom) + custom_ssvc[dtype].push(dtdp); + }); + }) + localStorage.setItem("custom_ssvc", JSON.stringify(custom_ssvc)); + form.parentElement.querySelector("[data-session]").style.display = "block"; } - return dtold; - } -function import_json(json, name) { - /* Convert everything to JSON 2.0.0 schema before loading */ - let outcomeName = "Priority"; - if(('schemaVersion' in json) && (json.schemaVersion == "2.0.0")) { - if(('outcome' in json) && ('decision_points' in json) && - (json.outcome in json.decision_points)) { - if('name' in json) - name = json.name; - else - name = "Custom Uploaded "; - SSVC.form.innerHTML = ""; - createSSVC(json, false); - /* Insert a new element in the array*/ - let fIndex = SSVC.decision_trees.findIndex(function(dtobj) { - return match_name_ns_vers(dtobj,json); - }); - if(fIndex < 0) { - const newname = name_version(json); - Object.values(json.decision_points).forEach(function(newdp) { - if(!(SSVC.decision_points.some(function(dtobj) { - return match_name_ns_vers(dtobj,newdp); - }))) { - if(!newdp.version) - newdp.version = "1.0.0"; - SSVC.decision_points.push({data: newdp}); - } - }); - selectCustom(newname, json, -1*(SSVC.decision_trees.length)); - SSVC.decision_trees.push({data:json,displayname: newname}); - } else { - const select = SSVC.form.parentElement.querySelector("[id='sampletrees']"); - select.value = fIndex; - select.dispatchEvent(new Event('change')); - topalert("Imported JSON is already in the registry","warn"); +function load_trees() { + if(!form) + return; + const sampletrees = form.parentElement.querySelector("[id='sampletrees']"); + sampletrees.innerHTML = ""; + const displaySet = {}; + decision_trees.forEach(function(decision_tree, i) { + const opt = new Option(decision_tree.displayname, i , decision_tree.selected, decision_tree.selected); + if(decision_tree.custom) { + opt.setAttribute("data-customdt","1"); + opt.innerText = "[Private] " +opt.innerText + } + if(displaySet[opt.innerText]) + opt.innerText = add_dash_n(opt.innerText, displaySet); + sampletrees.appendChild(opt); + if(decision_tree.selected) + loadSSVC(String(i)); + displaySet[opt.innerText] = 1; + }); + sampletrees.appendChild(new Option("Upload CSV/JSON","upload_file")); +} +async function delete_session() { + if(await popupConfirm("Are you sure, you want to delete all custom Decision Trees?") == "Yes") { + localStorage.removeItem("custom_ssvc"); + for (let i = 0; i < decision_trees.length; i++) { + if(decision_trees[i].custom) { + decision_trees.splice(i, 1); + i--; } } + topalert("All custom decision trees have been removed", "warn"); + load_trees(); + form.parentElement.querySelector("[data-session]").style.display = "none"; } else { - topalert("Unknown JSON file format","danger"); + topalert("Good! Custom decision trees have been retained!", "success", 3); } - } -function simpleCSV(csvString) { - const rows = []; - let row = []; - let value = ''; - let inQuotes = false; - - for (let i = 0; i < csvString.length; i++) { - const char = csvString[i]; - const nextChar = csvString[i + 1]; - - if (char === '"' && inQuotes && nextChar === '"') { - value += '"'; - i++; - } else if (char === '"') { - inQuotes = !inQuotes; - } else if (char === ',' && !inQuotes) { - row.push(value); - value = ''; - } else if ((char === '\n' || char === '\r') && !inQuotes) { - if (value || row.length > 0) { - row.push(value); - rows.push(row); - row = []; - value = ''; - } - if (char === '\r' && nextChar === '\n') i++; - } else { - value += char; - } - } - - if (value || row.length > 0) { - row.push(value); - rows.push(row); +async function delete_dtree() { + const sampletrees = form.parentElement.querySelector("[id='sampletrees']"); + const delete_tree = sampletrees.options[sampletrees.selectedIndex].innerText; + const opt = sampletrees.options[sampletrees.selectedIndex]; + if(!opt.hasAttribute("data-customdt")) { + return alert("The default trees cannot be deleted"); } - - return rows; -} - -function readFile(input) { - const file = input.files[0]; - const reader = new FileReader(); - const name = file.name; - reader.readAsText(file); - reader.onload = function() { - const data = reader.result; - if(data.match(/^\s*\{/)) { - const json = JSON.parse(data); - import_json(json, name); - } else { - /* Assume CSV convert it to JSON schema version 2.0.0*/ - const rows = simpleCSV(data); - let json = simpleCopy(SSVC.decision_trees[0].data); - json.decision_points = {}; - json.mapping = []; - json.name = name.substr(0,name.lastIndexOf('.')); - json.key = uniq_key({name: json.name}, SSVC.decision_trees.map(x => x.data)); - json.namespace = SSVC.default_namespace + "/csvupload"; - json.definition = json.name + " uploaded as CSV"; - let headers = rows.shift(); - let hasrowIndex = false; - if(headers[0] == "row") { - headers.shift(); - hasrowIndex = true; - } - let keymap = []; - headers.forEach(function(header,i ) { - let head = header; - if(header.indexOf(":") > -1) - head = header.split(":")[1]; - let dpkey = uniq_key({name:head},Object.values(json.decision_points)); - keymap[i] = json.namespace.substr(0,3) + ":" + dpkey + ":1.0.0"; - json.decision_points[keymap[i]] = {name: head, namespace: json.namespace, - definition: head, - key: dpkey}; - }); - json.outcome = keymap.at(-1); - let valueSet = result = Array.from({ length: headers.length }, () => []); - let mapping = []; - rows.forEach(function(row) { - let nmap = {} - row.forEach(function(value,i) { - if(!valueSet[i].some(function(values) { return values.name == value})) { - let mkey = uniq_key({name:value}, valueSet[i]); - valueSet[i].push({name: value, definition: value, - key: mkey}); - nmap[keymap[i]] = mkey; - } else { - let lfind = valueSet[i].find(function(valset) { - return valset.name == value; - }); - nmap[keymap[i]] = lfind.key; - } - - }); - mapping.push(nmap); - }); - json.mapping = mapping; - console.log(json,valueSet); - for(let i=0; i { - const key = feature.join(','); - if (!rules[key]) rules[key] = {}; - rules[key][labels[i]] = (rules[key][labels[i]] || 0) + 1; - }); - - this.rules = {}; - for (const key in rules) { - const outcomes = rules[key]; - this.rules[key] = Object.keys(outcomes).reduce((a, b) => - outcomes[a] > outcomes[b] ? a : b - ); - } - }; - - this.predict = function (feature) { - const key = feature.join(','); - return this.rules[key] || 'unknown'; - }; + if(await popupConfirm("Are you sure, you want to delete custom Decision Tree \""+ delete_tree + "\"?") == "Yes") { + let old_tree = simpleCopy(decision_tree[parseInt(opt.value)]); + decision_tree.splice(parseInt(opt.value), 1); + sampletrees.options[sampletrees.selectedIndex].remove(); + sampletrees.dispatchEvent(new Event("change")); + const saved = JSON.parse(localStorage.getItem("custom_ssvc")); + let savedIndex = saved.decision_trees.findIndex(function(dt) { + return match_name_ns_vers(dt,old_tree.data); + }); + if(savedIndex > -1) + saved.decision_trees.splice(savedIndex,1); + localStorage.setItem("custom_ssvc", JSON.stringify(saved)); + } else { + topalert("Good! Nothing was deleted!", "success", 3); } - - /* Calculate Accuracy */ - function calculateAccuracy(model, features, labels) { - const predictions = features.map(row => model.predict(row)); - const correct = predictions.filter((pred, i) => pred === labels[i]).length; - return correct / labels.length; +} +function rename_dtree() { + const sampletrees = form.parentElement.querySelector("[id='sampletrees']"); + const opt = sampletrees.options[sampletrees.selectedIndex]; + if(!opt.hasAttribute("data-customdt")) { + alert("The default trees cannot be deleted"); + return; + } + const old_index = parseInt(sampletrees.options[sampletrees.selectedIndex].value); + if(decision_trees[old_index] && decision_trees[old_index].data) { + const old_tree = decision_trees[old_index]; + const old_name = old_tree.data.name; + const new_name = prompt("Enter new name for the current decision tree \"" + old_name + "\":"); + decision_trees[old_index].data.name = new_name; + opt.innerText = name_version(decision_trees[old_index].data); + decision_trees[old_index].displayname = opt.innerText; + const saved = JSON.parse(localStorage.getItem("custom_ssvc")); + let savedIndex = saved.decision_trees.findIndex(function(dt) { + return match_name_ns_vers(dt,old_tree.data); + }); + if(savedIndex > -1) + saved.decision_trees[savedIndex] = decision_trees[old_index]; + localStorage.setItem("custom_ssvc", JSON.stringify(saved)); } - const classifier = new DecisionTreeClassifier(); - classifier.train(features, labels); - const baselineAccuracy = calculateAccuracy(classifier, features, labels); - featureNames = Object.keys(SSVC.decision_table[0]); - featureNames.pop() - const fI = featureNames.map((feature, index) => { - const reducedFeatures = features.map(row => row.filter((_, colIndex) => colIndex !== index)); - - const reducedClassifier = new DecisionTreeClassifier(); - reducedClassifier.train(reducedFeatures, labels); - - const reducedAccuracy = calculateAccuracy(reducedClassifier, reducedFeatures, labels); - - return { - feature, - importance: baselineAccuracy - reducedAccuracy - }; - }); - return fI; } -function fun_execute(w) { - if(w.selectedIndex) { - try { - let find_fun = new Function("return " + w.value + "()"); - find_fun(); - } catch(err) { - console.log("Error when trying to find dynamic function ", err); +function download_ssvc_csv() { + download_ssvc('csv'); +} +function download_ssvc_json() { + download_ssvc('json'); +} +function download_ssvc(dtype) { + const btn = form.parentElement.querySelector("[data-download-" + dtype + "]"); + btn.click(); +} +function restore_session() { + if(localStorage.getItem("custom_ssvc")) { + const saved = JSON.parse(localStorage.getItem("custom_ssvc")); + delete saved.form; + ["decision_points","decision_trees"].forEach(function(item) { + console.log(saved[item]); + SSVC[item].push.apply(SSVC[item],saved[item]); + }); + load_trees(); + topalert("Session variables have been restored!","success",3); + } else { + topalert("No previous session has been found to restore!","danger"); + } +} + function ssvc_launch() { + form = document.getElementById('ssvcForm'); + if(decision_trees.length < 1) + get_decision_points(); + else + load_trees(); + if(form && localStorage.getItem("custom_ssvc")) { + topalert("You have some custom Decision Trees saved from earlier session. " + + "use \"Restore Session\" under \"Custom Trees\" to restore & manage these", + "success",0); + form.parentElement.querySelector("[data-session]").style.display = "block"; } - w.selectedIndex = 0; } + document$.subscribe(function() { + ssvc_launch(); + }); +function dpValueClone(el) { + const pDiv = el.parentElement.parentElement; + pDiv.querySelectorAll("span").forEach(function(x) { x.remove(); }); + const count = pDiv.querySelectorAll("[data-clone]").length/2 - 1; + const delspan = document.createElement("span"); + delspan.innerHTML = "⊖"; + delspan.addEventListener("click", function(ev) { + const el = this; + el.parentElement.parentElement.nextSibling.remove(); + el.parentElement.parentElement.remove(); + }); + delspan.style.color = "red"; + [el.parentElement.nextElementSibling, + el.parentElement.nextElementSibling.nextElementSibling].forEach(function(row,i) { + const nrow = row.cloneNode(true); + const nel = nrow.querySelector("input,textarea"); + nel.value = ""; + if(nel.onchange) + nel.onchange(nel); + nel.name = nel.name.replace(/(\d+)([^\d]*)$/, function(_,n,g) { + return String(count + 1)+g + }); + nrow.setAttribute("data-temp","1"); + if (i == 0) + nrow.children[0].prepend(delspan); + pDiv.appendChild(nrow); + }); } -const graphModule = (function() { - const showFullTree = true; - const acolors = [ "#28a745", "#72b741", "#b0c13f", "#e6be3d", "#ffc107", - "#fba145", "#f37d4f", "#e65b53", "#d93f4e", "#dc3545"]; - const lcolors = {}; - let raw; - let treeData; - let selector = '#graph'; - - - function pathclick() {}; - function showdiv() {}; - function hidediv() {}; - function dorightclick() {}; - function doclick() {}; - function togglehelp() {}; - function create_raw(dt) { - const kmap = {}; - Object.entries(dt.decision_points).forEach(([k, v]) => { - kmap[k] = v.name; - }); - function find_value(k, dp) { - let dpm = dp.values.find(dpv => dpv.key == k); - if(dpm) - return dpm.name; - } - let thash = {}; - let dps = Object.keys(dt.decision_points); - let yraw = dps.map(x => []); - let zraw = []; - const final_k = dt.outcome; - const dpo = dt.decision_points[final_k]; - const ocolors = arrayReduce(acolors,dpo.values.length); - dpo.values.forEach(function(dpv,i) { - lcolors[dpv.name] = ocolors[i]; - }); - dt.decision_points[final_k].values.forEacj - const final_keyword = dt.decision_points[final_k].name; - const mapping = dt.mapping; - let id = 1; - for(let i=0; i find_value(dt.mapping[i][t],dt.decision_points[t])) - .slice(0,-1).join(":"); - for( let j=0; j< dps.length-1; j++) { - const tparent = dt.decision_points[dps[dps.length-2-j]].name + ":" + - dps.slice(0,dps.length-2-j).map(q => - find_value(dt.mapping[i][q],dt.decision_points[q])).join(":"); - if(!(tname in thash)) - var yt = {name:tname.replace(/\:+$/,''), - id:id++, - parent:tparent.replace(/\:+$/,''), - props:"{}",children:[]} +function textAreaAutoSize(element) { + element.style.height = "1px"; + element.style.height = String(4 + element.scrollHeight) + "px"; +} +function set_deep(obj,prop,val) { + /* For the Object obj set the property of a prop to val + recursively. example set_deep({a:{b:{c:{"good"}}}},"a-b-c","bad") + will return {a:{b:{c:{"bad"}}}} */ + if(typeof(obj) != "object") + return undefined; + let fobj = simpleCopy(obj); + var x = fobj; + let props = prop.split("-"); + let fprop = props.pop(); + for(var i=0; i -1; j--) { - if(yraw.length > 0) - zraw = zraw.concat(yraw[j]) + } + /* If the value is being set to be undefined then delete this property + of this object */ + if(val === undefined) { + if (fprop.match(/^\d+$/)) { + x.splice(parseInt(fprop),1); + } else { + delete x[fprop]; } - zraw[0] = {name:dt.decision_points[dps[0]].name,id:id+254,children:[],parent:null,props:"{}"} - return zraw; + } else { + x[fprop] = val; } - - function grapharray_open(marray){ - var map = {}; - for(var i = 0; i < marray.length; i++){ - var obj = marray[i]; - obj.children= []; - - map[obj.name] = obj; - - var parent = obj.parent || '-'; - if(!map[parent]){ - map[parent] = { - children: [] - }; + return fobj; +} +function deepGet(inputs) { + let fdp = {}; + inputs.forEach(function(input) { + fdp = set_deep(fdp,input.name,input.value); + }); + if(fdp.obj) + return fdp.obj; + return {}; +} +function makeTree(jsonTree) { + const clbutton = form.parentElement.querySelector("[data-clear]"); + jsonTree.mapping = []; + jsonTree.mapping = enumerateCombinations(jsonTree); + form.innerHTML = ""; + jsonTree.key = uniq_key(jsonTree, decision_trees.map(x => x.data),"DT_", 2); + console.log(jsonTree); + createSSVC(jsonTree, false); + customize({innerHTML: "Customize"}); + clbutton.setAttribute("data-changed","1"); + topalert(); + topalert("New Decision Tree has Outcomes that are evenly laid out! Please update these " + + "as appropriate for your Decision Model, before Saving it!","warn",0); +} +async function deleteDP(el) { + const dpName = el.parentElement.childNodes[0].textContent; + const confirm = await popupConfirm('Do you want to delete Decision Point "' + dpName + '"'); + if(confirm == "Yes") { + try { + const delDP = el.parentElement.getAttribute("data-dp"); + const alldps = Array.from(form.querySelectorAll("main [data-dp]")).map(function(el) { return el.getAttribute("data-dp")}); + if(alldps.length < 3) { + topalert("Minimum two decision points are needed", "danger"); + return false; } - map[parent].children.push(obj); + const removedp = JSON.parse(el.parentElement.parentElement.getAttribute("data-help")); + console.log(removedp); + const clbutton = form.parentElement.querySelector("[data-clear]"); + const jsonTree = JSON.parse(clbutton.getAttribute("data-json")); + const matched = Object.keys(jsonTree.decision_points).some(function(dpkey) { + const dp = jsonTree.decision_points[dpkey]; + if(match_name_ns_vers({data: dp},removedp)) { + delete jsonTree.decision_points[dpkey]; + return true; + } + return false; + }); + if(matched) + makeTree(jsonTree); + else + throw "Could not delete decision point"; + } catch(err) { + topalert(err,"danger"); } - return map['-'].children; } - - function draw_graph() { - var margin = {top: 20, right: 120, bottom: 20, left: 120}, - width = 1060 - margin.right - margin.left, - height = 800 - margin.top - margin.bottom - if(showFullTree) { - var add_offset = 0 - if(raw.length > 60 ) - add_offset = (raw.length - 60)*5 - height = 1300 - margin.top - margin.bottom + add_offset - } - duration = 750 - tree = d3.layout.tree() - .size([height, width]); - - diagonal = d3.svg.diagonal() - .projection(function(d) { return [d.y, d.x]; }); - - var default_translate = "translate(" + margin.left + "," + margin.top + ")" - var svg_width = width + margin.right + margin.left - var svg_height = height + margin.top + margin.bottom - if(window.innerWidth <= 1000) { - default_translate = "translate(10,0) scale(0.75)" - if(window.innerWidth <= 750) - default_translate = "translate(30,0) scale(0.42)" - } - let zdiv = $('
').css({position: "absolute"}); - let zinp = $('').attr({type: 'range', - min: '0', - max: '100', - value: '100', - accentColor: 'lightskyblue', - orient: 'vertical', - alt: 'Zoom Graph', - title: 'Zoom Graph'}); - zinp[0].onclick = function() { - const zf = this.value/this.max; - const fh = parseInt($('svg.mgraph').attr("height")); - const fw = parseInt($('svg.mgraph').attr("width")); - const vbox = "0 0 "+String(parseInt(fw/zf)) + " " + String(parseInt(fh/zf)) - $('svg.mgraph').attr('viewBox',vbox); +} +function find_key(dp,dt) { + /* Find a decision points' key attribute in a decision tree*/ + if('decision_points' in dt) { + for (const [fkey, fdp] of Object.entries(dt.decision_points)) { + if(['name','namespace','version'].every(function(prop) { + return prop in fdp && prop in dp && dp[prop] == fdp[prop]; + })) + return fkey; } - $(selector).html('').append(zdiv.append(zinp)); - svg = d3.select(selector).append("svg") - .attr("xmlns","http://www.w3.org/2000/svg") - .attr("preserveAspectRatio","none") - .attr("class","mgraph") - .attr("width", svg_width) - .attr("height", svg_height) - .append("g") - .attr("transform", default_translate) - .attr("id","pgroup"); - - root = treeData[0]; - root.x0 = height / 2; - root.y0 = 0; - - update(root) - - d3.select(self.frameElement).style("height", "700px"); } + return; +} +function uniq_key(obj, arr, prefix, copyLength) { + if(!prefix) + prefix = ""; + if(copyLength && String(copyLength).match(/^[0-9]$/)) { + copyLength = parseInt(copyLength); + } else { + copyLength = 1; + } + let base = obj.name.normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .replace(/[^a-zA-Z0-9_]/g, "") + .toUpperCase(); - function update(source) { - var i = 0 - var nodes = tree.nodes(root).reverse() - var links = tree.links(nodes) - - nodes.forEach(function(d) { d.y = d.depth * 200;}) - - var node = svg.selectAll("g.node") - .data(nodes, function(d) { return d.id || (d.id = ++i); }); - - var nodeEnter = node.enter().append("g") - .attr("class", "node bof") - .attr("transform", function(d) { - return "translate(" + source.y0 + "," + source.x0 + ")"; - }) - .attr("class", function(d) { - var finale = ""; - if(!('children' in d)) - finale = " finale"; - if('depth' in d) - return "node depth-"+String(d.depth)+finale; - return "node depth-none";}) - .on("click", doclick) - .on("contextmenu",dorightclick) - .on("mouseover",showdiv) - .on("mouseout",hidediv); - nodeEnter.append("circle") - .attr("r", 1e-6) - .attr("class",function(d, i) { - if(!('children' in d)) - return "junction gvisible finale "; - return "junction gvisible" - }) - .style("fill", function(d, i) { - if(d._children) return "lightsteelblue" - if(!('children' in d)) { - /* Last node no children */ - var dname = d.name.split(":").shift(); - if(dname in lcolors) - return undefined; - } - return undefined; - } ); - - var font = "20px" - if(showFullTree) - font = "18px" - nodeEnter.append("text") - .attr("x",function(d) { return check_children(d,"-55","+20") }) - .attr("y",function(d) { return check_children(d,"-37","0") }) - .attr("dy", ".35em") - .attr("class",function(d) { - var fclass = d.name.split(":").shift().toLowerCase(); - if(!('children' in d)) - return "gvisible prechk-"+fclass+" finale"; - return "gvisible prechk-"+fclass;}) - .text(function(d) { return d.name.split(":")[0]; }) - .style("font-size",font) - .style("fill", function(d) { - var t = d.name.split(":").shift(); - var x; - if(t in lcolors) - x = lcolors[t]; - return x; - }) - - /* hidden circle */ - nodeEnter.append("circle") - .attr("r","10") - .attr("class","ghidden d-none") - .style("fill","steelblue"); - - var nodeUpdate = node.transition() - .duration(duration) - .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); - - nodeUpdate.select("circle") - .attr("r", 10) - .attr("sid",function(d) { return d.id;}) - .attr("nameid",function(d) { if(!d) return "1"; - if(d.name) return d.name.split(":").pop(); - }) - .style("fill", function(d) { - if(d._children) return "lightsteelblue" - if(!('children' in d)) { - var dname = d.name.split(":").shift() - if(dname in lcolors) - return lcolors[dname]; - } - return undefined; - }) - .style("stroke",function(d) { - if(!('children' in d)) { - var dname = d.name.split(":").shift() - if(dname in lcolors) - return undefined; - } - return "steelblue"; - }) + if (copyLength && copyLength > 0) { + base = base.substring(0, copyLength); + } + if (!base[0] || !/[A-Z0-9]/.test(base[0])) { + base = "A" + base; + } - nodeUpdate.select("text") - .style("fill-opacity", 1); + if (base.length === 0) { + base = "A"; + } - var nodeExit = node.exit().transition() - .duration(duration) - .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) - .remove(); + let xkey = prefix + base; + let counter = 0; - nodeExit.select("circle") - .attr("r", 1e-6); + while (arr.findIndex(xdp => xdp.key === xkey) > -1) { + counter++; + xkey = prefix + base + "_" + counter; + } - nodeExit.select("text") - .style("fill-opacity", 1e-6); + return xkey; +} - var link = svg.selectAll("path.link") - .data(links, function(d) { if(d.target) return d.target.id; }) - link.enter().insert("path","g") - .style("fill","none").style("stroke", "#ccc").attr("class","link") - .attr("id", function(d) { return 'l'+Math.random().toString(36).substr(3); }) - .attr("kdata", function(d) { return d.source.name.split(":").shift(); }) - .attr("ldata", function(d) { return d.target.name.split(":").pop(); }) - .attr("ldeep", function (d) { return d.target.name.split(":").length }) - .attr("csid",function(d) { return d.target.id;}) - .attr("d", function(d) { - var o = {x: source.x0, y: source.y0}; - return diagonal({source: o, target: o}); - }) +function validate_namespace(namespace) { + if(!namespace.toLowerCase().startsWith("x_")) { + /* Only thing allowed is translation */ + if(!namespace.match(/\/[a-z\-0-9]*\//i)) { + alert("Changed Decision Point or Tree Namespace cannot use reserved namespaces. Either use x_com.example#psirt format or a pure translation ssvc/de-DE/ is allowed."); + return false; + } + } + return true; +} +function enumerateCombinations(dtree) { + const decisionPoints = dtree.decision_points; + const outcomeKey = dtree.outcome; - link.transition() - .duration(duration) - .attr("d", diagonal); + const relevantPoints = Object.entries(decisionPoints) + .filter(([key]) => key !== outcomeKey); - link.exit().transition() - .duration(duration) - .attr("d", function(d) { - var o = {x: source.x, y: source.y}; - return diagonal({source: o, target: o}); - }) - .remove(); + const pointsWithValues = relevantPoints.map(([id, dp]) => ({ + id: id, + values: dp.values.map(v => v.key) + })); - nodes.forEach(function(d) { - d.x0 = d.x; - d.y0 = d.y; - }); - if(showFullTree === false) { - var d = source; - if(('depth' in d) && (!isNaN(parseInt(d.depth)))) { - $('g.depth-'+String(d.depth)+' .ghidden').addClass('d-none'); - $('g.depth-'+String(d.depth)+' .gvisible').show(); - $('g.depth-'+String(d.depth)).removeClass('opthide'); - var idepth = String(parseInt(d.depth) + 1) - if($('g.depth-'+idepth).length > 0) { - $('g.depth-'+idepth+' .ghidden').removeClass('d-none'); - $('g.depth-'+idepth+' .gvisible').hide(); - $('g.depth-'+idepth).addClass('opthide'); - } - } + function cartesianProduct(index, current, result) { + if (index === pointsWithValues.length) { + current[outcomeKey] = "0"; + result.push(Object.assign({}, current)); + return; } - setTimeout(update_links,1500); - var xMin = d3.min(nodes, function(d) { return d.x; }); - var xMax = d3.max(nodes, function(d) { return d.x; }); - var yOffset = 90; - var xOffset = -xMin + yOffset; - svg.attr("transform", "translate(" + 100 + "," + xOffset + ")"); + const point = pointsWithValues[index]; + Array.from(point.values).forEach(function (value) { + current[point.id] = value; + cartesianProduct(index + 1, current, result); + }); } - function check_children(d,a,b) { - if((d.children) && (d.children.length)) return a - if((d._children) && (d._children.length)) return a - return b + + const result = []; + cartesianProduct(0, {}, result); + + const outcomeValues = decisionPoints[outcomeKey].values.map(v => v.key); + const outcomeCount = outcomeValues.length; + /* Spread outcome evenly across the results array*/ + const m = result.length; + const n = outcomeValues.length; + const blockSize = Math.floor(m / n); + let remainder = m % n; + + let index = 0; + for (let i = 0; i < n; i++) { + let size = blockSize + (remainder > 0 ? 1 : 0); + remainder = Math.max(0, remainder - 1); + + for (let j = 0; j < size; j++) { + result[index][outcomeKey] = outcomeValues[i]; + index++; + } } + return result; +} - function arrayReduce(arr,n) { - if(n > arr.length) - return arr.concat(Array(n-arr.length).fill(arr.at(-1))) - return arr.filter(function(_,i) { - if (i === 0 || i === arr.length - 1) return true; - const step = (arr.length-1)/(n-1); - for (let j = 1; j < n - 1; j++) - if (Math.round(j * step) === i) + +function updateTree() { + const clbutton = form.parentElement.querySelector("[data-clear]"); + clbutton.removeAttribute("data-changed") + let jsonTree = {}; + if(clbutton.hasAttribute("data-json")) { + jsonTree = JSON.parse(clbutton.getAttribute("data-json")); + } + const popUp = form.parentElement.parentElement.querySelector("[id='ssvcPopup']"); + const updatebtn = popUp.querySelector("[data-update]"); + const dpForm = popUp.querySelector("[data-customdp]") + .querySelector("form"); + const dpSelect = dpForm.querySelector("select"); + const dpOutcome = dpSelect.getAttribute("data-outcomeName"); + let changed = false; + const inputs = dpForm.querySelectorAll("input,textarea"); + let dp = deepGet(inputs); + for(let i=0; i x.data)); + const info = dp.namespace + "/" + name_version(dp); + let opt = Array.from(dpSelect.querySelectorAll("option")) + .filter(function(x) { + return x.innerText == info + }); + if(opt.length) { + opt[0].value = JSON.stringify(dp); + } else { + opt = new Option(info, JSON.stringify(dp)); + dpSelect.appendChild(opt); + } + decision_points.push({"filename": "memory:" + dp.namespace + + dp.name, "data": dp, custom: 1}); + } + if(oldKey) { + /* This is to replace a decision point */ + const oldvalues = simpleCopy(jsonTree.decision_points[oldKey].values); + delete jsonTree.decision_points[oldKey]; + let newKey = dp.namespace + ":" + dp.key + ":" + dp.version; + if(dp.namespace.indexOf("x_") > -1) + newKey = dp.namespace.substr(0,3) + ":" + dp.key + ":" + dp.version; + jsonTree.decision_points[newKey] = dp; + if(dpOutcome) { + jsonTree.outcome = newKey; + } + if (olddp.values && olddp.values.length == dp.values.length) { + /* Leave the Tree Outcomes as-is*/ + if(jsonTree.mapping.every(function(tmap,i) { + let fI = oldvalues.findIndex(value => value.key == tmap[oldKey]) + if(fI > -1) { + delete jsonTree.mapping[i][oldKey]; + tmap[newKey] = dp.values[fI].key; return true; - return false; + } + return false; + })) { + console.log("success"); + form.innerHTML = ""; + jsonTree.key = uniq_key(jsonTree, decision_trees.map(x => x.data),"DT_", 2); + createSSVC(jsonTree, false); + customize({innerHTML: "Customize"}); + clbutton.setAttribute("data-changed","1") + return; + } else { + console.log("Failed"); + console.log(jsonTree,dp); + } + } + } else if(updatebtn.innerText == "Add") { + if(!dp.version) + dp.version = "1.0.0"; + const newKey = dp.namespace + ":" + dp.key + ":" + dp.version; + jsonTree.decision_points[newKey] = dp; + } else { + topalert("Error: Unable to find if this is a new Decision Point or a replacement", + "danger"); + } + /* Somethings have majorly changed, we have to update the decision tree mappings */ + makeTree(jsonTree); +} +function schemaTransform(dtnew) { + const dtobj = simpleCopy(dtnew); + const dtold = {}; + let outcomeName; + if('outcome' in dtobj) + outcomeName = dtobj.outcome; + if('decision_points' in dtobj) { + dtold['decision_points'] = []; + Object.entries(dtobj['decision_points']).forEach(function([k,dp]) { + dp.decision_type = "simple"; + if(k == outcomeName) + dp.decision_type = "final"; + dp.values.forEach(function(dv) { + dv.label = dv.name; + delete dv.name; + }); + dp.options = dp.values; + delete dp.values; + dp.label = dp.name.replaceAll(",","|"); + delete dp.name; + dtold.decision_points.push(dp); + }); + } + if('mapping' in dtobj) { + dtold['decisions_table'] = []; + dtobj.mapping.forEach(function(dvpair) { + const dt = {} + Object.entries(dvpair).forEach(function([k,v]) { + const dp = dtnew.decision_points[k]; + const name = dp.name.replaceAll(",","|"); + for(let i=0; i< dp.values.length; i++) { + if('key' in dp.values[i] && dp.values[i].key == v) + dt[name] = dp.values[i].name; + } + }); + dtold['decisions_table'].push(dt); }); } + return dtold; + +} +function import_json(json, name) { + /* Convert everything to JSON 2.0.0 schema before loading */ + let outcomeName = "Priority"; + if(('schemaVersion' in json) && (json.schemaVersion == "2.0.0")) { + if(('outcome' in json) && ('decision_points' in json) && + (json.outcome in json.decision_points)) { + if('name' in json) + name = json.name; + else + name = "Custom Uploaded "; + form.innerHTML = ""; + createSSVC(json, false); + /* Insert a new element in the array*/ + let fIndex = decision_trees.findIndex(function(dtobj) { + return match_name_ns_vers(dtobj,json); + }); + if(fIndex < 0) { + const newname = name_version(json); + Object.values(json.decision_points).forEach(function(newdp) { + if(!(decision_points.some(function(dtobj) { + return match_name_ns_vers(dtobj,newdp); + }))) { + if(!newdp.version) + newdp.version = "1.0.0"; + decision_points.push({data: newdp}); + } + }); + selectCustom(newname, json, -1*(decision_trees.length)); + decision_trees.push({data:json,displayname: newname}); + } else { + const select = form.parentElement.querySelector("[id='sampletrees']"); + select.value = fIndex; + select.dispatchEvent(new Event('change')); + topalert("Imported JSON is already in the registry","warn"); + } + } + } else { + topalert("Unknown JSON file format","danger"); + } - function dt_graph(dt) { - raw = create_raw(dt); - treeData = grapharray_open(raw); - draw_graph(); +} +function simpleCSV(csvString) { + const rows = []; + let row = []; + let value = ''; + let inQuotes = false; + + for (let i = 0; i < csvString.length; i++) { + const char = csvString[i]; + const nextChar = csvString[i + 1]; + + if (char === '"' && inQuotes && nextChar === '"') { + value += '"'; + i++; + } else if (char === '"') { + inQuotes = !inQuotes; + } else if (char === ',' && !inQuotes) { + row.push(value); + value = ''; + } else if ((char === '\n' || char === '\r') && !inQuotes) { + if (value || row.length > 0) { + row.push(value); + rows.push(row); + row = []; + value = ''; + } + if (char === '\r' && nextChar === '\n') i++; + } else { + value += char; + } } - function update_links() { - $('.pathlink').remove() - var i = 0 - d3.selectAll("path.link").each(function(w) { - var t = $(this); - var id=t.attr("id"); - var xd = t.attr("d") - var csid = t.attr("csid") - var depth = parseInt(t.attr("ldeep")) || 0 - var text = t.attr("ldata") - var pname = t.attr("kdata") - var xclass = "btext prechk-"+text - var mclass = $(this).attr("class") - if((mclass) && mclass.indexOf("chosen") > -1) { - xclass += " chosen" - } - if(showFullTree) - xclass += " fullTree" - d3.select("g") - .insert("g","path.link").attr("class","pathlink cdepth-"+String(depth)).attr("id","x"+id) - .append("path").attr("d",xd).attr("id","f"+id) - .style("fill","none").style("stroke","#ccc") - .attr("class","xlink"); - var doffset = parseInt(70 - (4-depth)*5.5) - var yoffset = -10 - if(showFullTree) - yoffset = -6 - d3.select("g#x"+id).append("text").attr("dx",-6).attr("dy",yoffset).attr("class","gtext") - .append("textPath").attr("href","#f"+id).attr("class",xclass) - .attr("text-anchor","middle") - .attr("id","t"+id) - .attr("csid",csid) - .attr("parentname",pname) - .text(text).attr("startOffset",doffset+"%") - .on("click",pathclick) - .on("mouseover",showdiv) - .on("mouseout",hidediv); - }); + if (value || row.length > 0) { + row.push(value); + rows.push(row); } - function graph_dynamic(input) { - const dpContainer = input.parentElement.parentElement.parentElement; - const finddpIndex = $(input).data("dpdepth"); - const nodes = d3.selectAll("g.node.depth-"+String(finddpIndex)); - function traverse_remove(xnode) { - if(!xnode.__data__) { - console.log("Error no nodes to descend!"); - } - if(!xnode.__data__._schildren) { - console.log("Error no node _schildren data to restore from!"); + + return rows; +} + +function readFile(input) { + const file = input.files[0]; + const reader = new FileReader(); + const name = file.name; + reader.readAsText(file); + reader.onload = function() { + const data = reader.result; + if(data.match(/^\s*\{/)) { + const json = JSON.parse(data); + import_json(json, name); + } else { + /* Assume CSV convert it to JSON schema version 2.0.0*/ + const rows = simpleCSV(data); + let json = simpleCopy(decision_trees[0].data); + json.decision_points = {}; + json.mapping = []; + json.name = name.substr(0,name.lastIndexOf('.')); + json.key = uniq_key({name: json.name}, decision_trees.map(x => x.data)); + json.namespace = default_namespace + "/csvupload"; + json.definition = json.name + " uploaded as CSV"; + let headers = rows.shift(); + let hasrowIndex = false; + if(headers[0] == "row") { + headers.shift(); + hasrowIndex = true; } - let removeValues = []; - xnode.__data__.children = Array.from(xnode.__data__._schildren); - dpContainer.querySelectorAll("input").forEach(function(cinput) { - if(!cinput.checked) - removeValues.push($(cinput).data("dpvdepth")); - }); - removeValues.reverse().forEach(function(rindex) { - removevalueIndex = parseInt(rindex); - xnode.__data__.children.splice(removevalueIndex,1); + let keymap = []; + headers.forEach(function(header,i ) { + let head = header; + if(header.indexOf(":") > -1) + head = header.split(":")[1]; + let dpkey = uniq_key({name:head},Object.values(json.decision_points)); + keymap[i] = json.namespace.substr(0,3) + ":" + dpkey + ":1.0.0"; + json.decision_points[keymap[i]] = {name: head, namespace: json.namespace, + definition: head, + key: dpkey}; }); - update(xnode.__data__); - } - if(nodes.length) { - nodes[0].forEach(function(xnode) { - if(xnode.__data__) { - if(xnode.__data__._schildren) { - traverse_remove(xnode); - } else if(xnode.__data__.children) { - let removevalueIndex = $(input).data("dpvdepth"); - xnode.__data__._schildren = Array.from(xnode.__data__.children); - xnode.__data__.children.splice(removevalueIndex,1); - update(xnode.__data__); + json.outcome = keymap.at(-1); + let valueSet = result = Array.from({ length: headers.length }, () => []); + let mapping = []; + rows.forEach(function(row) { + let nmap = {} + row.forEach(function(value,i) { + if(!valueSet[i].some(function(values) { return values.name == value})) { + let mkey = uniq_key({name:value}, valueSet[i]); + valueSet[i].push({name: value, definition: value, + key: mkey}); + nmap[keymap[i]] = mkey; + } else { + let lfind = valueSet[i].find(function(valset) { + return valset.name == value; + }); + nmap[keymap[i]] = lfind.key; } - } + + }); + mapping.push(nmap); }); + json.mapping = mapping; + console.log(json,valueSet); + for(let i=0; i { + const key = feature.join(','); + if (!rules[key]) rules[key] = {}; + rules[key][labels[i]] = (rules[key][labels[i]] || 0) + 1; + }); + + this.rules = {}; + for (const key in rules) { + const outcomes = rules[key]; + this.rules[key] = Object.keys(outcomes).reduce((a, b) => + outcomes[a] > outcomes[b] ? a : b + ); + } + }; + + this.predict = function (feature) { + const key = feature.join(','); + return this.rules[key] || 'unknown'; + }; } + /* Calculate Accuracy */ + function calculateAccuracy(model, features, labels) { + const predictions = features.map(row => model.predict(row)); + const correct = predictions.filter((pred, i) => pred === labels[i]).length; + return correct / labels.length; + } + const classifier = new DecisionTreeClassifier(); + classifier.train(features, labels); + const baselineAccuracy = calculateAccuracy(classifier, features, labels); + featureNames = Object.keys(decision_table[0]); + featureNames.pop() + const fI = featureNames.map((feature, index) => { + const reducedFeatures = features.map(row => row.filter((_, colIndex) => colIndex !== index)); + + const reducedClassifier = new DecisionTreeClassifier(); + reducedClassifier.train(reducedFeatures, labels); + + const reducedAccuracy = calculateAccuracy(reducedClassifier, reducedFeatures, labels); + + return { + feature, + importance: baselineAccuracy - reducedAccuracy + }; + }); + return fI; +} +function fun_execute(w) { + if(w.selectedIndex) { + try { + let find_fun = new Function("return " + w.value + "()"); + find_fun(); + } catch(err) { + console.log("Error when trying to find dynamic function ", err); + } + w.selectedIndex = 0; + } +} return { - graph_dynamic: graph_dynamic, - dt_graph: dt_graph, - selector: "#graph", - __version__: "1.0.9" - }; + ssvc_launch: ssvc_launch, + decision_trees: decision_trees, + form: form, + loadSSVC: loadSSVC, + readFile: readFile, + customize: customize, + fun_execute: fun_execute, + toggleAll: toggleAll, + updateTree: updateTree, + popupEnd: popupEnd, + textAreaAutoSize: textAreaAutoSize, + dpValueClone: dpValueClone, + __version__: __version__ + } })(); diff --git a/docs/tutorials/starting_points.md b/docs/tutorials/starting_points.md index 2c187555..fa4ca031 100644 --- a/docs/tutorials/starting_points.md +++ b/docs/tutorials/starting_points.md @@ -25,10 +25,10 @@ For technical reference, including a list of decision points, see [Reference](.. The decisions modeled in the calculator are based on the [Supplier](../howto/supplier_tree.md), [Deployer](../howto/deployer_tree.md), and [Coordinator](../howto/coordination_intro.md) decision models. -!!! tip "SSVC Policy Explorer" +!!! tip "SSVC Explorer" - Ready to explore analyzing SSVC policies and writing your own policy? [SSVC Policy Explorer](../ssvc-explorer/index.md) to help you understand how SSVC decision models can be developed, organized in an interactive way. - The decisions modeled in the policy explorer also use the SSVC Registry. + Ready to explore analyzing SSVC policies and writing your own policy? [SSVC Explorer](../ssvc-explorer/index.md) to help you understand how SSVC decision models can be developed, organized in an interactive way. + The decisions modeled in the SSVC Explorer also use the SSVC Registry. SSVC can be used in conjunction with other tools and methodologies to help prioritize vulnerability response. diff --git a/mkdocs.yml b/mkdocs.yml index 48103a27..db1b780c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -140,10 +140,9 @@ nav: - Namespaces: 'reference/code/namespaces.md' - Selections: 'reference/code/selection.md' - CSV Analyzer: 'reference/code/analyze_csv.md' - - Policy Generator: 'reference/code/policy_generator.md' - Doctools: 'reference/code/doctools.md' - Calculator: 'ssvc-calc/index.md' - - Policy Explorer: 'ssvc-explorer/index.md' + - Explorer: 'ssvc-explorer/index.md' - About: - Intro: 'about/index.md' - Community Engagement: 'about/contributing.md' @@ -258,6 +257,10 @@ extra_javascript: # to sort tables - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js - javascripts/tablesort.js + # scripts for graphModule and Explorer + - ssvc-explorer/simple.js + - https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js + - https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js extra_css: - stylesheets/extra.css watch: diff --git a/requirements.txt b/requirements.txt index 9e875a7d..cd326bef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,9 +31,9 @@ backrefs==5.9 \ --hash=sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9 \ --hash=sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60 # via mkdocs-material -beautifulsoup4==4.13.4 \ - --hash=sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b \ - --hash=sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195 +beautifulsoup4==4.13.5 \ + --hash=sha256:5e70131382930e7c3de33450a2f54a63d5e4b19386eab43a5b34d594268f3695 \ + --hash=sha256:642085eaa22233aceadff9c69651bc51e8bf3f874fb6d7104ece2beb24b47c4a # via linkchecker bracex==2.6 \ --hash=sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952 \ @@ -103,37 +103,37 @@ colorama==0.4.6 \ # mkdocs-material # pytest # uvicorn -dnspython==2.7.0 \ - --hash=sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86 \ - --hash=sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1 +dnspython==2.8.0 \ + --hash=sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af \ + --hash=sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f # via # email-validator # linkchecker -email-validator==2.2.0 \ - --hash=sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631 \ - --hash=sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7 +email-validator==2.3.0 \ + --hash=sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4 \ + --hash=sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426 # via # fastapi # pydantic -fastapi==0.116.1 \ - --hash=sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565 \ - --hash=sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143 +fastapi==0.117.1 \ + --hash=sha256:33c51a0d21cab2b9722d4e56dbb9316f3687155be6b276191790d8da03507552 \ + --hash=sha256:fb2d42082d22b185f904ca0ecad2e195b851030bd6c5e4c032d1c981240c631a # via certcc-ssvc -fastapi-cli==0.0.8 \ - --hash=sha256:0ea95d882c85b9219a75a65ab27e8da17dac02873e456850fa0a726e96e985eb \ - --hash=sha256:2360f2989b1ab4a3d7fc8b3a0b20e8288680d8af2e31de7c38309934d7f8a0ee +fastapi-cli==0.0.13 \ + --hash=sha256:219b73ccfde7622559cef1d43197da928516acb4f21f2ec69128c4b90057baba \ + --hash=sha256:312addf3f57ba7139457cf0d345c03e2170cc5a034057488259c33cd7e494529 # via fastapi -fastapi-cloud-cli==0.1.5 \ - --hash=sha256:341ee585eb731a6d3c3656cb91ad38e5f39809bf1a16d41de1333e38635a7937 \ - --hash=sha256:d80525fb9c0e8af122370891f9fa83cf5d496e4ad47a8dd26c0496a6c85a012a +fastapi-cloud-cli==0.2.0 \ + --hash=sha256:115d9b1f198b09ecc66f67156d183babb4fc14431414cc2e57a7649624782da6 \ + --hash=sha256:8dc13f95246d80e625e2789a21760494e855d887f70caae109423d00064772d1 # via fastapi-cli ghp-import==2.1.0 \ --hash=sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619 \ --hash=sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343 # via mkdocs -griffe==1.12.1 \ - --hash=sha256:29f5a6114c0aeda7d9c86a570f736883f8a2c5b38b57323d56b3d1c000565567 \ - --hash=sha256:2d7c12334de00089c31905424a00abcfd931b45b8b516967f224133903d302cc +griffe==1.14.0 \ + --hash=sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0 \ + --hash=sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13 # via mkdocstrings-python h11==0.16.0 \ --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ @@ -192,17 +192,17 @@ jinja2==3.1.6 \ # mkdocs # mkdocs-material # mkdocstrings -joblib==1.5.1 \ - --hash=sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a \ - --hash=sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444 +joblib==1.5.2 \ + --hash=sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55 \ + --hash=sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241 # via scikit-learn jsonschema==4.25.1 \ --hash=sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63 \ --hash=sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85 # via certcc-ssvc -jsonschema-specifications==2025.4.1 \ - --hash=sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af \ - --hash=sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608 +jsonschema-specifications==2025.9.1 \ + --hash=sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe \ + --hash=sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d # via jsonschema latexcodec==3.0.1 \ --hash=sha256:a9eb8200bff693f0437a69581f7579eb6bca25c4193515c09900ce76451e452e \ @@ -211,9 +211,9 @@ latexcodec==3.0.1 \ linkchecker==10.6.0 \ --hash=sha256:5268587ed0b0f7e7521b75905128c96856f30f67dad49f66e2c963bc174ca92d \ --hash=sha256:fb7e8facda7749c2fa5fa5dc241c0adc302da3d31d588964a2570db501aa49e5 -markdown==3.8.2 \ - --hash=sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45 \ - --hash=sha256:5c83764dbd4e00bdd94d85a19b8d55ccca20fe35b2e678a1422b380324dd5f24 +markdown==3.9 \ + --hash=sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280 \ + --hash=sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a # via # mkdocs # mkdocs-autorefs @@ -286,9 +286,9 @@ mkdocs==1.6.1 \ # mkdocs-material # mkdocs-table-reader-plugin # mkdocstrings -mkdocs-autorefs==1.4.2 \ - --hash=sha256:83d6d777b66ec3c372a1aad4ae0cf77c243ba5bcda5bf0c6b8a2c5e7a3d89f13 \ - --hash=sha256:e2ebe1abd2b67d597ed19378c0fff84d73d1dbce411fce7a7cc6f161888b6749 +mkdocs-autorefs==1.4.3 \ + --hash=sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9 \ + --hash=sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75 # via # mkdocstrings # mkdocstrings-python @@ -300,9 +300,9 @@ mkdocs-get-deps==0.2.0 \ --hash=sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c \ --hash=sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134 # via mkdocs -mkdocs-include-markdown-plugin==7.1.6 \ - --hash=sha256:7975a593514887c18ecb68e11e35c074c5499cfa3e51b18cd16323862e1f7345 \ - --hash=sha256:a0753cb82704c10a287f1e789fc9848f82b6beb8749814b24b03dd9f67816677 +mkdocs-include-markdown-plugin==7.2.0 \ + --hash=sha256:4a67a91ade680dc0e15f608e5b6343bec03372ffa112c40a4254c1bfb10f42f3 \ + --hash=sha256:d56cdaeb2d113fb66ed0fe4fb7af1da889926b0b9872032be24e19bbb09c9f5b # via certcc-ssvc mkdocs-material==9.6.18 \ --hash=sha256:a2eb253bcc8b66f8c6eaf8379c10ed6e9644090c2e2e9d0971c7722dc7211c05 \ @@ -338,110 +338,110 @@ networkx==3.4.2 \ --hash=sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1 \ --hash=sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f # via certcc-ssvc -numpy==2.3.2 \ - --hash=sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5 \ - --hash=sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b \ - --hash=sha256:092aeb3449833ea9c0bf0089d70c29ae480685dd2377ec9cdbbb620257f84631 \ - --hash=sha256:095737ed986e00393ec18ec0b21b47c22889ae4b0cd2d5e88342e08b01141f58 \ - --hash=sha256:0a4f2021a6da53a0d580d6ef5db29947025ae8b35b3250141805ea9a32bbe86b \ - --hash=sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc \ - --hash=sha256:11e58218c0c46c80509186e460d79fbdc9ca1eb8d8aee39d8f2dc768eb781089 \ - --hash=sha256:122bf5ed9a0221b3419672493878ba4967121514b1d7d4656a7580cd11dddcbf \ - --hash=sha256:2738534837c6a1d0c39340a190177d7d66fdf432894f469728da901f8f6dc910 \ - --hash=sha256:27c9f90e7481275c7800dc9c24b7cc40ace3fdb970ae4d21eaff983a32f70c91 \ - --hash=sha256:293b2192c6bcce487dbc6326de5853787f870aeb6c43f8f9c6496db5b1781e45 \ - --hash=sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f \ - --hash=sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b \ - --hash=sha256:448a66d052d0cf14ce9865d159bfc403282c9bc7bb2a31b03cc18b651eca8b1a \ - --hash=sha256:4d002ecf7c9b53240be3bb69d80f86ddbd34078bae04d87be81c1f58466f264e \ - --hash=sha256:4e6ecfeddfa83b02318f4d84acf15fbdbf9ded18e46989a15a8b6995dfbf85ab \ - --hash=sha256:508b0eada3eded10a3b55725b40806a4b855961040180028f52580c4729916a2 \ - --hash=sha256:546aaf78e81b4081b2eba1d105c3b34064783027a06b3ab20b6eba21fb64132b \ - --hash=sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370 \ - --hash=sha256:5ad4ebcb683a1f99f4f392cc522ee20a18b2bb12a2c1c42c3d48d5a1adc9d3d2 \ - --hash=sha256:66459dccc65d8ec98cc7df61307b64bf9e08101f9598755d42d8ae65d9a7a6ee \ - --hash=sha256:6f1ae3dcb840edccc45af496f312528c15b1f79ac318169d094e85e4bb35fdf1 \ - --hash=sha256:72c6df2267e926a6d5286b0a6d556ebe49eae261062059317837fda12ddf0c1a \ - --hash=sha256:72dbebb2dcc8305c431b2836bcc66af967df91be793d63a24e3d9b741374c450 \ - --hash=sha256:754d6755d9a7588bdc6ac47dc4ee97867271b17cee39cb87aef079574366db0a \ - --hash=sha256:76c3e9501ceb50b2ff3824c3589d5d1ab4ac857b0ee3f8f49629d0de55ecf7c2 \ - --hash=sha256:7d6e390423cc1f76e1b8108c9b6889d20a7a1f59d9a60cac4a050fa734d6c1e2 \ - --hash=sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73 \ - --hash=sha256:87c930d52f45df092f7578889711a0768094debf73cfcde105e2d66954358125 \ - --hash=sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0 \ - --hash=sha256:8dc082ea901a62edb8f59713c6a7e28a85daddcb67454c839de57656478f5b19 \ - --hash=sha256:906a30249315f9c8e17b085cc5f87d3f369b35fedd0051d4a84686967bdbbd0b \ - --hash=sha256:938065908d1d869c7d75d8ec45f735a034771c6ea07088867f713d1cd3bbbe4f \ - --hash=sha256:9c144440db4bf3bb6372d2c3e49834cc0ff7bb4c24975ab33e01199e645416f2 \ - --hash=sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f \ - --hash=sha256:a3ef07ec8cbc8fc9e369c8dcd52019510c12da4de81367d8b20bc692aa07573a \ - --hash=sha256:a7af9ed2aa9ec5950daf05bb11abc4076a108bd3c7db9aa7251d5f107079b6a6 \ - --hash=sha256:a9f66e7d2b2d7712410d3bc5684149040ef5f19856f20277cd17ea83e5006286 \ - --hash=sha256:af58de8745f7fa9ca1c0c7c943616c6fe28e75d0c81f5c295810e3c83b5be92f \ - --hash=sha256:b05a89f2fb84d21235f93de47129dd4f11c16f64c87c33f5e284e6a3a54e43f2 \ - --hash=sha256:b5e40e80299607f597e1a8a247ff8d71d79c5b52baa11cc1cce30aa92d2da6e0 \ - --hash=sha256:b9d0878b21e3918d76d2209c924ebb272340da1fb51abc00f986c258cd5e957b \ - --hash=sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b \ - --hash=sha256:c63d95dc9d67b676e9108fe0d2182987ccb0f11933c1e8959f42fa0da8d4fa56 \ - --hash=sha256:c771cfac34a4f2c0de8e8c97312d07d64fd8f8ed45bc9f5726a7e947270152b5 \ - --hash=sha256:c8d9727f5316a256425892b043736d63e89ed15bbfe6556c5ff4d9d4448ff3b3 \ - --hash=sha256:cefc2219baa48e468e3db7e706305fcd0c095534a192a08f31e98d83a7d45fb0 \ - --hash=sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036 \ - --hash=sha256:dd937f088a2df683cbb79dda9a772b62a3e5a8a7e76690612c2737f38c6ef1b6 \ - --hash=sha256:de6ea4e5a65d5a90c7d286ddff2b87f3f4ad61faa3db8dabe936b34c2275b6f8 \ - --hash=sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48 \ - --hash=sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07 \ - --hash=sha256:efc81393f25f14d11c9d161e46e6ee348637c0a1e8a54bf9dedc472a3fae993b \ - --hash=sha256:f92d6c2a8535dc4fe4419562294ff957f83a16ebdec66df0805e473ffaad8bd0 \ - --hash=sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be \ - --hash=sha256:fed5527c4cf10f16c6d0b6bee1f89958bccb0ad2522c8cadc2efd318bcd545f5 +numpy==2.3.3 \ + --hash=sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b \ + --hash=sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54 \ + --hash=sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5 \ + --hash=sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970 \ + --hash=sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8 \ + --hash=sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3 \ + --hash=sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e \ + --hash=sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe \ + --hash=sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5 \ + --hash=sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b \ + --hash=sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652 \ + --hash=sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d \ + --hash=sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb \ + --hash=sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7 \ + --hash=sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a \ + --hash=sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf \ + --hash=sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93 \ + --hash=sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8 \ + --hash=sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19 \ + --hash=sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1 \ + --hash=sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b \ + --hash=sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d \ + --hash=sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc \ + --hash=sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86 \ + --hash=sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097 \ + --hash=sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a \ + --hash=sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7 \ + --hash=sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30 \ + --hash=sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c \ + --hash=sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8 \ + --hash=sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe \ + --hash=sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00 \ + --hash=sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6 \ + --hash=sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe \ + --hash=sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd \ + --hash=sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae \ + --hash=sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f \ + --hash=sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a \ + --hash=sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5 \ + --hash=sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0 \ + --hash=sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25 \ + --hash=sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593 \ + --hash=sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea \ + --hash=sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421 \ + --hash=sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf \ + --hash=sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7 \ + --hash=sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7 \ + --hash=sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf \ + --hash=sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20 \ + --hash=sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e \ + --hash=sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029 \ + --hash=sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021 \ + --hash=sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea \ + --hash=sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc \ + --hash=sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf \ + --hash=sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf # via # pandas # scikit-learn # scipy -orjson==3.11.2 \ - --hash=sha256:07349e88025b9b5c783077bf7a9f401ffbfb07fd20e86ec6fc5b7432c28c2c5e \ - --hash=sha256:0afb89f16f07220183fd00f5f297328ed0a68d8722ad1b0c8dcd95b12bc82804 \ - --hash=sha256:13d8d8db6cd8d89d4d4e0f4161acbbb373a4d2a4929e862d1d2119de4aa324ac \ - --hash=sha256:15d17bdb76a142e1f55d91913e012e6e6769659daa6bfef3ef93f11083137e81 \ - --hash=sha256:191ed27a1dddb305083d8716af413d7219f40ec1d4c9b0e977453b4db0d6fb6c \ - --hash=sha256:21cf261e8e79284242e4cb1e5924df16ae28255184aafeff19be1405f6d33f67 \ - --hash=sha256:24e32a558ebed73a6a71c8f1cbc163a7dd5132da5270ff3d8eeb727f4b6d1bc7 \ - --hash=sha256:26693dde66910078229a943e80eeb99fdce6cd2c26277dc80ead9f3ab97d2131 \ - --hash=sha256:29d91d74942b7436f29b5d1ed9bcfc3f6ef2d4f7c4997616509004679936650d \ - --hash=sha256:2cc42960515076eb639b705f105712b658c525863d89a1704d984b929b0577d1 \ - --hash=sha256:3dcba7101ea6a8d4ef060746c0f2e7aa8e2453a1012083e1ecce9726d7554cb7 \ - --hash=sha256:40193ada63fab25e35703454d65b6afc71dbc65f20041cb46c6d91709141ef7f \ - --hash=sha256:45841fbb79c96441a8c58aa29ffef570c5df9af91f0f7a9572e5505e12412f15 \ - --hash=sha256:4ad4c8acb50a28211c33fc7ef85ddf5cb18d4636a5205fd3fa2dce0411a0e30c \ - --hash=sha256:4ca4fb5ac21cd1e48028d4f708b1bb13e39c42d45614befd2ead004a8bba8535 \ - --hash=sha256:50995bbeb5d41a32ad15e023305807f561ac5dcd9bd41a12c8d8d1d2c83e44e6 \ - --hash=sha256:51da1ee2178ed09c00d09c1b953e45846bbc16b6420965eb7a913ba209f606d8 \ - --hash=sha256:51dc033df2e4a4c91c0ba4f43247de99b3cbf42ee7a42ee2b2b2f76c8b2f2cb5 \ - --hash=sha256:53c9e81768c69d4b66b8876ec3c8e431c6e13477186d0db1089d82622bccd19f \ - --hash=sha256:59f8d5ad08602711af9589375be98477d70e1d102645430b5a7985fdbf613b36 \ - --hash=sha256:6a5f62ebbc530bb8bb4b1ead103647b395ba523559149b91a6c545f7cd4110ad \ - --hash=sha256:6ab6e6b4e93b1573a026b6ec16fca9541354dd58e514b62c558b58554ae04307 \ - --hash=sha256:6f59dfea7da1fced6e782bb3699718088b1036cb361f36c6e4dd843c5111aefe \ - --hash=sha256:7c8ac5f6b682d3494217085cf04dadae66efee45349ad4ee2a1da3c97e2305a8 \ - --hash=sha256:901d80d349d8452162b3aa1afb82cec5bee79a10550660bc21311cc61a4c5486 \ - --hash=sha256:91bdcf5e69a8fd8e8bdb3de32b31ff01d2bd60c1e8d5fe7d5afabdcf19920309 \ - --hash=sha256:994181e7f1725bb5f2d481d7d228738e0743b16bf319ca85c29369c65913df14 \ - --hash=sha256:9cb23527efb61fb75527df55d20ee47989c4ee34e01a9c98ee9ede232abf6219 \ - --hash=sha256:a079fdba7062ab396380eeedb589afb81dc6683f07f528a03b6f7aae420a0219 \ - --hash=sha256:a4dd1268e4035af21b8a09e4adf2e61f87ee7bf63b86d7bb0a237ac03fad5b45 \ - --hash=sha256:ae3bb10279d57872f9aba68c9931aa71ed3b295fa880f25e68da79e79453f46e \ - --hash=sha256:b5ca86300aeb383c8fa759566aca065878d3d98c3389d769b43f0a2e84d52c5f \ - --hash=sha256:bde64aa469b5ee46cc960ed241fae3721d6a8801dacb2ca3466547a2535951e4 \ - --hash=sha256:c56777cab2a7b2a8ea687fedafb84b3d7fdafae382165c31a2adf88634c432fa \ - --hash=sha256:cf3bd3967a360e87ee14ed82cb258b7f18c710dacf3822fb0042a14313a673a1 \ - --hash=sha256:d026e1967239ec11a2559b4146a61d13914504b396f74510a1c4d6b19dfd8732 \ - --hash=sha256:d4f13af59a7b84c1ca6b8a7ab70d608f61f7c44f9740cd42409e6ae7b6c8d8b7 \ - --hash=sha256:d7df6c7b8b0931feb3420b72838c3e2ba98c228f7aa60d461bc050cf4ca5f7b2 \ - --hash=sha256:dbb79a0476393c07656b69c8e763c3cc925fa8e1d9e9b7d1f626901bb5025448 \ - --hash=sha256:e36319a5d15b97e4344110517450396845cc6789aed712b1fbf83c1bd95792f6 \ - --hash=sha256:edf49146520fef308c31aa4c45b9925fd9c7584645caca7c0c4217d7900214ae \ - --hash=sha256:ff8b155b145eaf5a9d94d2c476fbe18d6021de93cf36c2ae2c8c5b775763f14e +orjson==3.11.3 \ + --hash=sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d \ + --hash=sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710 \ + --hash=sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f \ + --hash=sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce \ + --hash=sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a \ + --hash=sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077 \ + --hash=sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b \ + --hash=sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae \ + --hash=sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451 \ + --hash=sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804 \ + --hash=sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca \ + --hash=sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f \ + --hash=sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667 \ + --hash=sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27 \ + --hash=sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167 \ + --hash=sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1 \ + --hash=sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee \ + --hash=sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f \ + --hash=sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d \ + --hash=sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a \ + --hash=sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b \ + --hash=sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2 \ + --hash=sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc \ + --hash=sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43 \ + --hash=sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872 \ + --hash=sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e \ + --hash=sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be \ + --hash=sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810 \ + --hash=sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2 \ + --hash=sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424 \ + --hash=sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e \ + --hash=sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23 \ + --hash=sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d \ + --hash=sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4 \ + --hash=sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229 \ + --hash=sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633 \ + --hash=sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064 \ + --hash=sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc \ + --hash=sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049 \ + --hash=sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c \ + --hash=sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1 \ + --hash=sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c # via fastapi packaging==25.0 \ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ @@ -482,9 +482,9 @@ pathspec==0.12.1 \ --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08 \ --hash=sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712 # via mkdocs -platformdirs==4.3.8 \ - --hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \ - --hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4 +platformdirs==4.4.0 \ + --hash=sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85 \ + --hash=sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf # via mkdocs-get-deps pluggy==1.6.0 \ --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ @@ -568,9 +568,9 @@ pypandoc==1.15 \ --hash=sha256:4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16 \ --hash=sha256:ea25beebe712ae41d63f7410c08741a3cab0e420f6703f95bc9b3a749192ce13 # via mkdocs-bibtex -pytest==8.4.1 \ - --hash=sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7 \ - --hash=sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c +pytest==8.4.2 \ + --hash=sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01 \ + --hash=sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79 python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 @@ -625,38 +625,63 @@ pyyaml-env-tag==1.1 \ --hash=sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04 \ --hash=sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff # via mkdocs -rapidfuzz==3.13.0 \ - --hash=sha256:09e908064d3684c541d312bd4c7b05acb99a2c764f6231bd507d4b4b65226c23 \ - --hash=sha256:0da54aa8547b3c2c188db3d1c7eb4d1bb6dd80baa8cdaeaec3d1da3346ec9caa \ - --hash=sha256:0e1d08cb884805a543f2de1f6744069495ef527e279e05370dd7c83416af83f8 \ - --hash=sha256:11b125d8edd67e767b2295eac6eb9afe0b1cdc82ea3d4b9257da4b8e06077798 \ - --hash=sha256:11b47b40650e06147dee5e51a9c9ad73bb7b86968b6f7d30e503b9f8dd1292db \ - --hash=sha256:1343d745fbf4688e412d8f398c6e6d6f269db99a54456873f232ba2e7aeb4939 \ - --hash=sha256:1dc82b6ed01acb536b94a43996a94471a218f4d89f3fdd9185ab496de4b2a981 \ - --hash=sha256:2d18228a2390375cf45726ce1af9d36ff3dc1f11dce9775eae1f1b13ac6ec50f \ - --hash=sha256:2fd0975e015b05c79a97f38883a11236f5a24cca83aa992bd2558ceaa5652b26 \ - --hash=sha256:3f32f15bacd1838c929b35c84b43618481e1b3d7a61b5ed2db0291b70ae88b53 \ - --hash=sha256:461fd13250a2adf8e90ca9a0e1e166515cbcaa5e9c3b1f37545cbbeff9e77f6b \ - --hash=sha256:4671ee300d1818d7bdfd8fa0608580d7778ba701817216f0c17fb29e6b972514 \ - --hash=sha256:4a1a6a906ba62f2556372282b1ef37b26bca67e3d2ea957277cfcefc6275cca7 \ - --hash=sha256:57c390336cb50d5d3bfb0cfe1467478a15733703af61f6dffb14b1cd312a6fae \ - --hash=sha256:5d4e13593d298c50c4f94ce453f757b4b398af3fa0fd2fde693c3e51195b7f69 \ - --hash=sha256:65cc97c2fc2c2fe23586599686f3b1ceeedeca8e598cfcc1b7e56dc8ca7e2aa7 \ - --hash=sha256:694eb531889f71022b2be86f625a4209c4049e74be9ca836919b9e395d5e33b3 \ - --hash=sha256:6e2065f68fb1d0bf65adc289c1bdc45ba7e464e406b319d67bb54441a1b9da9e \ - --hash=sha256:98b8107ff14f5af0243f27d236bcc6e1ef8e7e3b3c25df114e91e3a99572da73 \ - --hash=sha256:9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264 \ - --hash=sha256:9f5fe634c9482ec5d4a6692afb8c45d370ae86755e5f57aa6c50bfe4ca2bdd87 \ - --hash=sha256:ae4574cb66cf1e85d32bb7e9ec45af5409c5b3970b7ceb8dea90168024127566 \ - --hash=sha256:b1b065f370d54551dcc785c6f9eeb5bd517ae14c983d2784c064b3aa525896df \ - --hash=sha256:b836f486dba0aceb2551e838ff3f514a38ee72b015364f739e526d720fdb823a \ - --hash=sha256:c2b3dd5d206a12deca16870acc0d6e5036abeb70e3cad6549c294eff15591527 \ - --hash=sha256:c33f9c841630b2bb7e69a3fb5c84a854075bb812c47620978bddc591f764da3d \ - --hash=sha256:d2eaf3839e52cbcc0accbe9817a67b4b0fcf70aaeb229cfddc1c28061f9ce5d8 \ - --hash=sha256:df8e8c21e67afb9d7fbe18f42c6111fe155e801ab103c81109a61312927cc611 \ - --hash=sha256:e05752418b24bbd411841b256344c26f57da1148c5509e34ea39c7eb5099ab72 \ - --hash=sha256:e9d824de871daa6e443b39ff495a884931970d567eb0dfa213d234337343835f \ - --hash=sha256:ed6f416bda1c9133000009d84d9409823eb2358df0950231cc936e4bf784eb97 +rapidfuzz==3.14.1 \ + --hash=sha256:01eab10ec90912d7d28b3f08f6c91adbaf93458a53f849ff70776ecd70dd7a7a \ + --hash=sha256:0591df2e856ad583644b40a2b99fb522f93543c65e64b771241dda6d1cfdc96b \ + --hash=sha256:07a9fad3247e68798424bdc116c1094e88ecfabc17b29edf42a777520347648e \ + --hash=sha256:0afcf2d6cb633d0d4260d8df6a40de2d9c93e9546e2c6b317ab03f89aa120ad7 \ + --hash=sha256:13e0ea3d0c533969158727d1bb7a08c2cc9a816ab83f8f0dcfde7e38938ce3e6 \ + --hash=sha256:26db0e815213d04234298dea0d884d92b9cb8d4ba954cab7cf67a35853128a33 \ + --hash=sha256:2e3e61c9e80d8c26709d8aa5c51fdd25139c81a4ab463895f8a567f8347b0548 \ + --hash=sha256:37017b84953927807847016620d61251fe236bd4bcb25e27b6133d955bb9cafb \ + --hash=sha256:40301b93b99350edcd02dbb22e37ca5f2a75d0db822e9b3c522da451a93d6f27 \ + --hash=sha256:40875e0c06f1a388f1cab3885744f847b557e0b1642dfc31ff02039f9f0823ef \ + --hash=sha256:4373f914ff524ee0146919dea96a40a8200ab157e5a15e777a74a769f73d8a4a \ + --hash=sha256:44e741d785de57d1a7bae03599c1cbc7335d0b060a35e60c44c382566e22782e \ + --hash=sha256:474f416cbb9099676de54aa41944c154ba8d25033ee460f87bb23e54af6d01c9 \ + --hash=sha256:4acc20776f225ee37d69517a237c090b9fa7e0836a0b8bc58868e9168ba6ef6f \ + --hash=sha256:57047493a1f62f11354c7143c380b02f1b355c52733e6b03adb1cb0fe8fb8816 \ + --hash=sha256:5967d571243cfb9ad3710e6e628ab68c421a237b76e24a67ac22ee0ff12784d6 \ + --hash=sha256:5c1c3d07d53dcafee10599da8988d2b1f39df236aee501ecbd617bd883454fcd \ + --hash=sha256:60879fcae2f7618403c4c746a9a3eec89327d73148fb6e89a933b78442ff0669 \ + --hash=sha256:61458e83b0b3e2abc3391d0953c47d6325e506ba44d6a25c869c4401b3bc222c \ + --hash=sha256:61c5b9ab6f730e6478aa2def566223712d121c6f69a94c7cc002044799442afd \ + --hash=sha256:61d77e09b2b6bc38228f53b9ea7972a00722a14a6048be9a3672fb5cb08bad3a \ + --hash=sha256:6325ca435b99f4001aac919ab8922ac464999b100173317defb83eae34e82139 \ + --hash=sha256:67ea46fa8cc78174bad09d66b9a4b98d3068e85de677e3c71ed931a1de28171f \ + --hash=sha256:6ad3395a416f8b126ff11c788531f157c7debeb626f9d897c153ff8980da10fb \ + --hash=sha256:6c7c26025f7934a169a23dafea6807cfc3fb556f1dd49229faf2171e5d8101cc \ + --hash=sha256:6cb56b695421538fdbe2c0c85888b991d833b8637d2f2b41faa79cea7234c000 \ + --hash=sha256:6e9ee3e1eb0a027717ee72fe34dc9ac5b3e58119f1bd8dd15bc19ed54ae3e62b \ + --hash=sha256:6f571d20152fc4833b7b5e781b36d5e4f31f3b5a596a3d53cf66a1bd4436b4f4 \ + --hash=sha256:70c845b64a033a20c44ed26bc890eeb851215148cc3e696499f5f65529afb6cb \ + --hash=sha256:7a2d80cc1a4fcc7e259ed4f505e70b36433a63fa251f1bb69ff279fe376c5efd \ + --hash=sha256:7cd312c380d3ce9d35c3ec9726b75eee9da50e8a38e89e229a03db2262d3d96b \ + --hash=sha256:809515194f628004aac1b1b280c3734c5ea0ccbd45938c9c9656a23ae8b8f553 \ + --hash=sha256:83b8cc6336709fa5db0579189bfd125df280a554af544b2dc1c7da9cdad7e44d \ + --hash=sha256:876dc0c15552f3d704d7fb8d61bdffc872ff63bedf683568d6faad32e51bbce8 \ + --hash=sha256:893fdfd4f66ebb67f33da89eb1bd1674b7b30442fdee84db87f6cb9074bf0ce9 \ + --hash=sha256:8b41d95ef86a6295d353dc3bb6c80550665ba2c3bef3a9feab46074d12a9af8f \ + --hash=sha256:8d69f470d63ee824132ecd80b1974e1d15dd9df5193916901d7860cef081a260 \ + --hash=sha256:93b6294a3ffab32a9b5f9b5ca048fa0474998e7e8bb0f2d2b5e819c64cb71ec7 \ + --hash=sha256:9c83270e44a6ae7a39fc1d7e72a27486bccc1fa5f34e01572b1b90b019e6b566 \ + --hash=sha256:ace21f7a78519d8e889b1240489cd021c5355c496cb151b479b741a4c27f0a25 \ + --hash=sha256:ae2d57464b59297f727c4e201ea99ec7b13935f1f056c753e8103da3f2fc2404 \ + --hash=sha256:b02850e7f7152bd1edff27e9d584505b84968cacedee7a734ec4050c655a803c \ + --hash=sha256:b1fe6001baa9fa36bcb565e24e88830718f6c90896b91ceffcb48881e3adddbc \ + --hash=sha256:c8d1dd1146539e093b84d0805e8951475644af794ace81d957ca612e3eb31598 \ + --hash=sha256:cb5acf24590bc5e57027283b015950d713f9e4d155fda5cfa71adef3b3a84502 \ + --hash=sha256:cf75769662eadf5f9bd24e865c19e5ca7718e879273dce4e7b3b5824c4da0eb4 \ + --hash=sha256:d937dbeda71c921ef6537c6d41a84f1b8112f107589c9977059de57a1d726dd6 \ + --hash=sha256:da011a373722fac6e64687297a1d17dc8461b82cb12c437845d5a5b161bc24b9 \ + --hash=sha256:e06664c7fdb51c708e082df08a6888fce4c5c416d7e3cc2fa66dd80eb76a149d \ + --hash=sha256:e84d9a844dc2e4d5c4cabd14c096374ead006583304333c14a6fbde51f612a44 \ + --hash=sha256:f277801f55b2f3923ef2de51ab94689a0671a4524bf7b611de979f308a54cd6f \ + --hash=sha256:f51c7571295ea97387bac4f048d73cecce51222be78ed808263b45c79c40a440 \ + --hash=sha256:f8ff5dbe78db0a10c1f916368e21d328935896240f71f721e073cf6c4c8cdedd \ + --hash=sha256:f94d61e44db3fc95a74006a394257af90fa6e826c900a501d749979ff495d702 \ + --hash=sha256:fe2651258c1f1afa9b66f44bf82f639d5f83034f9804877a1bbbae2120539ad1 \ + --hash=sha256:fedd5097a44808dddf341466866e5c57a18a19a336565b4ff50aa8f09eb528f6 # via thefuzz referencing==0.36.2 \ --hash=sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa \ @@ -682,9 +707,9 @@ rich==14.1.0 \ # via # rich-toolkit # typer -rich-toolkit==0.15.0 \ - --hash=sha256:3f5730e9f2d36d0bfe01cf723948b7ecf4cc355d2b71e2c00e094f7963128c09 \ - --hash=sha256:ddb91008283d4a7989fd8ff0324a48773a7a2276229c6a3070755645538ef1bb +rich-toolkit==0.15.1 \ + --hash=sha256:36a0b1d9a135d26776e4b78f1d5c2655da6e0ef432380b5c6b523c8d8ab97478 \ + --hash=sha256:6f9630eb29f3843d19d48c3bd5706a086d36d62016687f9d0efa027ddc2dd08a # via # fastapi-cli # fastapi-cloud-cli @@ -729,81 +754,81 @@ rignore==0.6.4 \ --hash=sha256:f5f9dca46fc41c0a1e236767f68be9d63bdd2726db13a0ae3a30f68414472969 \ --hash=sha256:feac73377a156fb77b3df626c76f7e5893d9b4e9e886ac8c0f9d44f1206a2a91 # via fastapi-cloud-cli -rpds-py==0.27.0 \ - --hash=sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b \ - --hash=sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51 \ - --hash=sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295 \ - --hash=sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d \ - --hash=sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e \ - --hash=sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd \ - --hash=sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5 \ - --hash=sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03 \ - --hash=sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9 \ - --hash=sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34 \ - --hash=sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1 \ - --hash=sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303 \ - --hash=sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4 \ - --hash=sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c \ - --hash=sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec \ - --hash=sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e \ - --hash=sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97 \ - --hash=sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd \ - --hash=sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432 \ - --hash=sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae \ - --hash=sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5 \ - --hash=sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828 \ - --hash=sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79 \ - --hash=sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89 \ - --hash=sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c \ - --hash=sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff \ - --hash=sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43 \ - --hash=sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1 \ - --hash=sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac \ - --hash=sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e \ - --hash=sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8 \ - --hash=sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64 \ - --hash=sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669 \ - --hash=sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3 \ - --hash=sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b \ - --hash=sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0 \ - --hash=sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858 \ - --hash=sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4 \ - --hash=sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f \ - --hash=sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d \ - --hash=sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5 \ - --hash=sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391 \ - --hash=sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f \ - --hash=sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f \ - --hash=sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774 \ - --hash=sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156 \ - --hash=sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185 \ - --hash=sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d \ - --hash=sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b \ - --hash=sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9 \ - --hash=sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2 \ - --hash=sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb \ - --hash=sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726 \ - --hash=sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23 \ - --hash=sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374 \ - --hash=sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367 \ - --hash=sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c \ - --hash=sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd \ - --hash=sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc \ - --hash=sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8 \ - --hash=sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a \ - --hash=sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e \ - --hash=sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6 \ - --hash=sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b \ - --hash=sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615 \ - --hash=sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2 \ - --hash=sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9 \ - --hash=sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015 \ - --hash=sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433 \ - --hash=sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb \ - --hash=sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410 \ - --hash=sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e \ - --hash=sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42 \ - --hash=sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe +rpds-py==0.27.1 \ + --hash=sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f \ + --hash=sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60 \ + --hash=sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2 \ + --hash=sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff \ + --hash=sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef \ + --hash=sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd \ + --hash=sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf \ + --hash=sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d \ + --hash=sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e \ + --hash=sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8 \ + --hash=sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5 \ + --hash=sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8 \ + --hash=sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418 \ + --hash=sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688 \ + --hash=sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502 \ + --hash=sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675 \ + --hash=sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a \ + --hash=sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734 \ + --hash=sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5 \ + --hash=sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92 \ + --hash=sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274 \ + --hash=sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3 \ + --hash=sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83 \ + --hash=sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817 \ + --hash=sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48 \ + --hash=sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772 \ + --hash=sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2 \ + --hash=sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802 \ + --hash=sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec \ + --hash=sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1 \ + --hash=sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a \ + --hash=sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39 \ + --hash=sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4 \ + --hash=sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797 \ + --hash=sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228 \ + --hash=sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881 \ + --hash=sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002 \ + --hash=sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998 \ + --hash=sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456 \ + --hash=sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd \ + --hash=sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e \ + --hash=sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334 \ + --hash=sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90 \ + --hash=sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2 \ + --hash=sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b \ + --hash=sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33 \ + --hash=sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2 \ + --hash=sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136 \ + --hash=sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212 \ + --hash=sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0 \ + --hash=sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb \ + --hash=sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a \ + --hash=sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21 \ + --hash=sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf \ + --hash=sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594 \ + --hash=sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e \ + --hash=sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7 \ + --hash=sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3 \ + --hash=sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723 \ + --hash=sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b \ + --hash=sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb \ + --hash=sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081 \ + --hash=sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7 \ + --hash=sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d \ + --hash=sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9 \ + --hash=sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444 \ + --hash=sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a \ + --hash=sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0 \ + --hash=sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83 \ + --hash=sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3 \ + --hash=sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2 \ + --hash=sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a \ + --hash=sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb \ + --hash=sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec # via # jsonschema # referencing @@ -878,9 +903,9 @@ semver==3.0.4 \ --hash=sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746 \ --hash=sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602 # via certcc-ssvc -sentry-sdk==2.35.0 \ - --hash=sha256:5ea58d352779ce45d17bc2fa71ec7185205295b83a9dbb5707273deb64720092 \ - --hash=sha256:6e0c29b9a5d34de8575ffb04d289a987ff3053cf2c98ede445bea995e3830263 +sentry-sdk==2.38.0 \ + --hash=sha256:2324aea8573a3fa1576df7fb4d65c4eb8d9929c8fa5939647397a07179eef8d0 \ + --hash=sha256:792d2af45e167e2f8a3347143f525b9b6bac6f058fb2014720b40b84ccbeb985 # via fastapi-cloud-cli setuptools==80.9.0 \ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \ @@ -898,13 +923,13 @@ sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc # via anyio -soupsieve==2.7 \ - --hash=sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4 \ - --hash=sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a +soupsieve==2.8 \ + --hash=sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c \ + --hash=sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f # via beautifulsoup4 -starlette==0.47.2 \ - --hash=sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8 \ - --hash=sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b +starlette==0.48.0 \ + --hash=sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659 \ + --hash=sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46 # via fastapi tabulate==0.9.0 \ --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \ @@ -918,15 +943,15 @@ threadpoolctl==3.6.0 \ --hash=sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb \ --hash=sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e # via scikit-learn -typer==0.16.1 \ - --hash=sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9 \ - --hash=sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614 +typer==0.19.1 \ + --hash=sha256:914b2b39a1da4bafca5f30637ca26fa622a5bf9f515e5fdc772439f306d5682a \ + --hash=sha256:cb881433a4b15dacc875bb0583d1a61e78497806741f9aba792abcab390c03e6 # via # fastapi-cli # fastapi-cloud-cli -typing-extensions==4.14.1 \ - --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ - --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 +typing-extensions==4.15.0 \ + --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ + --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 # via # anyio # beautifulsoup4 @@ -949,28 +974,52 @@ tzdata==2025.2 \ --hash=sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8 \ --hash=sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9 # via pandas -ujson==5.10.0 \ - --hash=sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20 \ - --hash=sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc \ - --hash=sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e \ - --hash=sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539 \ - --hash=sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165 \ - --hash=sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816 \ - --hash=sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e \ - --hash=sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287 \ - --hash=sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0 \ - --hash=sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043 \ - --hash=sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557 \ - --hash=sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e \ - --hash=sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21 \ - --hash=sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5 \ - --hash=sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2 \ - --hash=sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e \ - --hash=sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1 \ - --hash=sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f \ - --hash=sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988 \ - --hash=sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3 \ - --hash=sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1 +ujson==5.11.0 \ + --hash=sha256:0180a480a7d099082501cad1fe85252e4d4bf926b40960fb3d9e87a3a6fbbc80 \ + --hash=sha256:04c41afc195fd477a59db3a84d5b83a871bd648ef371cf8c6f43072d89144eef \ + --hash=sha256:090b4d11b380ae25453100b722d0609d5051ffe98f80ec52853ccf8249dfd840 \ + --hash=sha256:109f59885041b14ee9569bf0bb3f98579c3fa0652317b355669939e5fc5ede53 \ + --hash=sha256:10f29e71ecf4ecd93a6610bd8efa8e7b6467454a363c3d6416db65de883eb076 \ + --hash=sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab \ + --hash=sha256:12b5e7e22a1fe01058000d1b317d3b65cc3daf61bd2ea7a2b76721fe160fa74d \ + --hash=sha256:1a0a9b76a89827a592656fe12e000cf4f12da9692f51a841a4a07aa4c7ecc41c \ + --hash=sha256:1a325fd2c3a056cf6c8e023f74a0c478dd282a93141356ae7f16d5309f5ff823 \ + --hash=sha256:1aa8a2ab482f09f6c10fba37112af5f957689a79ea598399c85009f2f29898b5 \ + --hash=sha256:1d663b96eb34c93392e9caae19c099ec4133ba21654b081956613327f0e973ac \ + --hash=sha256:29113c003ca33ab71b1b480bde952fbab2a0b6b03a4ee4c3d71687cdcbd1a29d \ + --hash=sha256:34032aeca4510a7c7102bd5933f59a37f63891f30a0706fb46487ab6f0edf8f0 \ + --hash=sha256:3772e4fe6b0c1e025ba3c50841a0ca4786825a4894c8411bf8d3afe3a8061328 \ + --hash=sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec \ + --hash=sha256:49e56ef8066f11b80d620985ae36869a3ff7e4b74c3b6129182ec5d1df0255f3 \ + --hash=sha256:4c9f5d6a27d035dd90a146f7761c2272cf7103de5127c9ab9c4cd39ea61e878a \ + --hash=sha256:65724738c73645db88f70ba1f2e6fb678f913281804d5da2fd02c8c5839af302 \ + --hash=sha256:6cd2df62f24c506a0ba322d5e4fe4466d47a9467b57e881ee15a31f7ecf68ff6 \ + --hash=sha256:6dd703c3e86dc6f7044c5ac0b3ae079ed96bf297974598116aa5fb7f655c3a60 \ + --hash=sha256:787aff4a84da301b7f3bac09bc696e2e5670df829c6f8ecf39916b4e7e24e701 \ + --hash=sha256:7895f0d2d53bd6aea11743bd56e3cb82d729980636cd0ed9b89418bf66591702 \ + --hash=sha256:78c684fb21255b9b90320ba7e199780f653e03f6c2528663768965f4126a5b50 \ + --hash=sha256:7e3cff632c1d78023b15f7e3a81c3745cd3f94c044d1e8fa8efbd6b161997bbc \ + --hash=sha256:80017e870d882d5517d28995b62e4e518a894f932f1e242cbc802a2fd64d365c \ + --hash=sha256:8254e858437c00f17cb72e7a644fc42dad0ebb21ea981b71df6e84b1072aaa7c \ + --hash=sha256:837da4d27fed5fdc1b630bd18f519744b23a0b5ada1bbde1a36ba463f2900c03 \ + --hash=sha256:849e65b696f0d242833f1df4182096cedc50d414215d1371fca85c541fbff629 \ + --hash=sha256:8fa2af7c1459204b7a42e98263b069bd535ea0cd978b4d6982f35af5a04a4241 \ + --hash=sha256:a0af6574fc1d9d53f4ff371f58c96673e6d988ed2b5bf666a6143c782fa007e9 \ + --hash=sha256:a31c6b8004438e8c20fc55ac1c0e07dad42941db24176fe9acf2815971f8e752 \ + --hash=sha256:a638425d3c6eed0318df663df44480f4a40dc87cc7c6da44d221418312f6413b \ + --hash=sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5 \ + --hash=sha256:ab2cb8351d976e788669c8281465d44d4e94413718af497b4e7342d7b2f78018 \ + --hash=sha256:b16930f6a0753cdc7d637b33b4e8f10d5e351e1fb83872ba6375f1e87be39746 \ + --hash=sha256:b7b136cc6abc7619124fd897ef75f8e63105298b5ca9bdf43ebd0e1fa0ee105f \ + --hash=sha256:be6b0eaf92cae8cdee4d4c9e074bde43ef1c590ed5ba037ea26c9632fb479c88 \ + --hash=sha256:c44c703842024d796b4c78542a6fcd5c3cb948b9fc2a73ee65b9c86a22ee3638 \ + --hash=sha256:ce076f2df2e1aa62b685086fbad67f2b1d3048369664b4cdccc50707325401f9 \ + --hash=sha256:de6e88f62796372fba1de973c11138f197d3e0e1d80bcb2b8aae1e826096d433 \ + --hash=sha256:e204ae6f909f099ba6b6b942131cee359ddda2b6e4ea39c12eb8b991fe2010e0 \ + --hash=sha256:e73df8648c9470af2b6a6bf5250d4744ad2cf3d774dcf8c6e31f018bdd04d764 \ + --hash=sha256:e750c436fb90edf85585f5c62a35b35082502383840962c6983403d1bd96a02c \ + --hash=sha256:f278b31a7c52eb0947b2db55a5133fbc46b6f0ef49972cd1a80843b72e135aba \ + --hash=sha256:fa79fdb47701942c2132a9dd2297a1a85941d966d8c87bfd9e29b0cf423f26cc # via fastapi urllib3==2.5.0 \ --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ @@ -979,9 +1028,9 @@ urllib3==2.5.0 \ # requests # responses # sentry-sdk -uvicorn==0.35.0 \ - --hash=sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a \ - --hash=sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01 +uvicorn==0.36.0 \ + --hash=sha256:527dc68d77819919d90a6b267be55f0e76704dca829d34aea9480be831a9b9d9 \ + --hash=sha256:6bb4ba67f16024883af8adf13aba3a9919e415358604ce46780d3f9bdc36d731 # via # fastapi # fastapi-cli diff --git a/src/pyproject.toml b/src/pyproject.toml index f32675dc..bf8874d3 100644 --- a/src/pyproject.toml +++ b/src/pyproject.toml @@ -29,24 +29,24 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", ] dependencies = [ - "mkdocs==1.6.1", - "mkdocs-material==9.6.18", - "mkdocs-material-extensions==1.3.1", - "mkdocstrings==0.30.0", - "mkdocstrings-python==1.17.0", - "mkdocs-include-markdown-plugin==7.1.6", - "pandas==2.3.2", - "scipy==1.16.1", - "jsonschema==4.25.1", - "mkdocs-bibtex==4.4.0", - "mkdocs-table-reader-plugin==3.1.0", - "mkdocs-print-site-plugin==2.8", - "markdown-exec[ansi]==1.11.0", - "thefuzz==0.22.1", - "scikit-learn==1.6.1", - "networkx==3.4.2", - "pydantic==2.11.7", - "semver==3.0.4", + "mkdocs>=1.6.1", + "mkdocs-material>=9.6.18", + "mkdocs-material-extensions>=1.3.1", + "mkdocstrings>=0.30.0", + "mkdocstrings-python>=1.17.0", + "mkdocs-include-markdown-plugin>=7.1.8", + "pandas>=2.3.2", + "scipy>=1.16.1", + "jsonschema>=4.25.1", + "mkdocs-bibtex>=4.4.0", + "mkdocs-table-reader-plugin>=3.1.0", + "mkdocs-print-site-plugin>=2.8", + "markdown-exec[ansi]>=1.11.0", + "thefuzz>=0.22.1", + "scikit-learn>=1.6.1", + "networkx>=3.4.2", + "pydantic>=2.11.7", + "semver>=3.0.4", "fastapi[all,standard]>=0.116.1", ] dynamic = ["version",] diff --git a/src/uv.lock b/src/uv.lock index f445f69c..c142f9eb 100644 --- a/src/uv.lock +++ b/src/uv.lock @@ -59,15 +59,15 @@ wheels = [ [[package]] name = "beautifulsoup4" -version = "4.13.4" +version = "4.13.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/2e/3e5079847e653b1f6dc647aa24549d68c6addb4c595cc0d902d1b19308ad/beautifulsoup4-4.13.5.tar.gz", hash = "sha256:5e70131382930e7c3de33450a2f54a63d5e4b19386eab43a5b34d594268f3695", size = 622954, upload-time = "2025-08-24T14:06:13.168Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, + { url = "https://files.pythonhosted.org/packages/04/eb/f4151e0c7377a6e08a38108609ba5cede57986802757848688aeedd1b9e8/beautifulsoup4-4.13.5-py3-none-any.whl", hash = "sha256:642085eaa22233aceadff9c69651bc51e8bf3f874fb6d7104ece2beb24b47c4a", size = 105113, upload-time = "2025-08-24T14:06:14.884Z" }, ] [[package]] @@ -79,6 +79,66 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" }, ] +[[package]] +name = "certcc-ssvc" +source = { editable = "." } +dependencies = [ + { name = "fastapi", extra = ["all", "standard"] }, + { name = "jsonschema" }, + { name = "markdown-exec", extra = ["ansi"] }, + { name = "mkdocs" }, + { name = "mkdocs-bibtex" }, + { name = "mkdocs-include-markdown-plugin" }, + { name = "mkdocs-material" }, + { name = "mkdocs-material-extensions" }, + { name = "mkdocs-print-site-plugin" }, + { name = "mkdocs-table-reader-plugin" }, + { name = "mkdocstrings" }, + { name = "mkdocstrings-python" }, + { name = "networkx" }, + { name = "pandas" }, + { name = "pydantic" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "semver" }, + { name = "thefuzz" }, +] + +[package.dev-dependencies] +dev = [ + { name = "linkchecker" }, + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastapi", extras = ["all", "standard"], specifier = ">=0.116.1" }, + { name = "jsonschema", specifier = ">=4.25.1" }, + { name = "markdown-exec", extras = ["ansi"], specifier = ">=1.11.0" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-bibtex", specifier = ">=4.4.0" }, + { name = "mkdocs-include-markdown-plugin", specifier = ">=7.1.8" }, + { name = "mkdocs-material", specifier = ">=9.6.18" }, + { name = "mkdocs-material-extensions", specifier = ">=1.3.1" }, + { name = "mkdocs-print-site-plugin", specifier = ">=2.8" }, + { name = "mkdocs-table-reader-plugin", specifier = ">=3.1.0" }, + { name = "mkdocstrings", specifier = ">=0.30.0" }, + { name = "mkdocstrings-python", specifier = ">=1.17.0" }, + { name = "networkx", specifier = ">=3.4.2" }, + { name = "pandas", specifier = ">=2.3.2" }, + { name = "pydantic", specifier = ">=2.11.7" }, + { name = "scikit-learn", specifier = ">=1.6.1" }, + { name = "scipy", specifier = ">=1.16.1" }, + { name = "semver", specifier = ">=3.0.4" }, + { name = "thefuzz", specifier = ">=0.22.1" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "linkchecker", specifier = ">=10.6.0" }, + { name = "pytest", specifier = ">=8.4.1" }, +] + [[package]] name = "certifi" version = "2025.8.3" @@ -153,38 +213,38 @@ wheels = [ [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, ] [[package]] name = "email-validator" -version = "2.2.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] [[package]] name = "fastapi" -version = "0.116.1" +version = "0.117.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/7e/d9788300deaf416178f61fb3c2ceb16b7d0dc9f82a08fdb87a5e64ee3cc7/fastapi-0.117.1.tar.gz", hash = "sha256:fb2d42082d22b185f904ca0ecad2e195b851030bd6c5e4c032d1c981240c631a", size = 307155, upload-time = "2025-09-20T20:16:56.663Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, + { url = "https://files.pythonhosted.org/packages/6d/45/d9d3e8eeefbe93be1c50060a9d9a9f366dba66f288bb518a9566a23a8631/fastapi-0.117.1-py3-none-any.whl", hash = "sha256:33c51a0d21cab2b9722d4e56dbb9316f3687155be6b276191790d8da03507552", size = 95959, upload-time = "2025-09-20T20:16:53.661Z" }, ] [package.optional-dependencies] @@ -213,16 +273,16 @@ standard = [ [[package]] name = "fastapi-cli" -version = "0.0.8" +version = "0.0.13" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/94/3ef75d9c7c32936ecb539b9750ccbdc3d2568efd73b1cb913278375f4533/fastapi_cli-0.0.8.tar.gz", hash = "sha256:2360f2989b1ab4a3d7fc8b3a0b20e8288680d8af2e31de7c38309934d7f8a0ee", size = 16884, upload-time = "2025-07-07T14:44:09.326Z" } +sdist = { url = "https://files.pythonhosted.org/packages/32/4e/3f61850012473b097fc5297d681bd85788e186fadb8555b67baf4c7707f4/fastapi_cli-0.0.13.tar.gz", hash = "sha256:312addf3f57ba7139457cf0d345c03e2170cc5a034057488259c33cd7e494529", size = 17780, upload-time = "2025-09-20T16:37:31.089Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/3f/6ad3103c5f59208baf4c798526daea6a74085bb35d1c161c501863470476/fastapi_cli-0.0.8-py3-none-any.whl", hash = "sha256:0ea95d882c85b9219a75a65ab27e8da17dac02873e456850fa0a726e96e985eb", size = 10770, upload-time = "2025-07-07T14:44:08.255Z" }, + { url = "https://files.pythonhosted.org/packages/08/36/7432750f3638324b055496d2c952000bea824259fca70df5577a6a3c172f/fastapi_cli-0.0.13-py3-none-any.whl", hash = "sha256:219b73ccfde7622559cef1d43197da928516acb4f21f2ec69128c4b90057baba", size = 11142, upload-time = "2025-09-20T16:37:29.695Z" }, ] [package.optional-dependencies] @@ -233,7 +293,7 @@ standard = [ [[package]] name = "fastapi-cloud-cli" -version = "0.1.5" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, @@ -244,9 +304,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/2e/3b6e5016affc310e5109bc580f760586eabecea0c8a7ab067611cd849ac0/fastapi_cloud_cli-0.1.5.tar.gz", hash = "sha256:341ee585eb731a6d3c3656cb91ad38e5f39809bf1a16d41de1333e38635a7937", size = 22710, upload-time = "2025-07-28T13:30:48.216Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/55/4e7541c006b492f000cd833bd1db43b587b85aef7f54fa4f63ad7cc7eb44/fastapi_cloud_cli-0.2.0.tar.gz", hash = "sha256:115d9b1f198b09ecc66f67156d183babb4fc14431414cc2e57a7649624782da6", size = 23637, upload-time = "2025-09-18T14:55:44.628Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/a6/5aa862489a2918a096166fd98d9fe86b7fd53c607678b3fa9d8c432d88d5/fastapi_cloud_cli-0.1.5-py3-none-any.whl", hash = "sha256:d80525fb9c0e8af122370891f9fa83cf5d496e4ad47a8dd26c0496a6c85a012a", size = 18992, upload-time = "2025-07-28T13:30:47.427Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5d/0ee71a1d67b5d028536eb1bc7e2be4409a5a7c4e529a9f74812472076832/fastapi_cloud_cli-0.2.0-py3-none-any.whl", hash = "sha256:8dc13f95246d80e625e2789a21760494e855d887f70caae109423d00064772d1", size = 19864, upload-time = "2025-09-18T14:55:43.365Z" }, ] [[package]] @@ -263,14 +323,14 @@ wheels = [ [[package]] name = "griffe" -version = "1.12.1" +version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/ca/29f36e00c74844ae50d139cf5a8b1751887b2f4d5023af65d460268ad7aa/griffe-1.12.1.tar.gz", hash = "sha256:29f5a6114c0aeda7d9c86a570f736883f8a2c5b38b57323d56b3d1c000565567", size = 411863, upload-time = "2025-08-14T21:08:15.38Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/f2/4fab6c3e5bcaf38a44cc8a974d2752eaad4c129e45d6533d926a30edd133/griffe-1.12.1-py3-none-any.whl", hash = "sha256:2d7c12334de00089c31905424a00abcfd931b45b8b516967f224133903d302cc", size = 138940, upload-time = "2025-08-14T21:08:13.382Z" }, + { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" }, ] [[package]] @@ -373,11 +433,11 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.1" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, ] [[package]] @@ -397,14 +457,14 @@ wheels = [ [[package]] name = "jsonschema-specifications" -version = "2025.4.1" +version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] [[package]] @@ -432,11 +492,11 @@ wheels = [ [[package]] name = "markdown" -version = "3.8.2" +version = "3.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/c2/4ab49206c17f75cb08d6311171f2d65798988db4360c4d1485bd0eedd67c/markdown-3.8.2.tar.gz", hash = "sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45", size = 362071, upload-time = "2025-06-19T17:12:44.483Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2b/34cc11786bc00d0f04d0f5fdc3a2b1ae0b6239eef72d3d345805f9ad92a1/markdown-3.8.2-py3-none-any.whl", hash = "sha256:5c83764dbd4e00bdd94d85a19b8d55ccca20fe35b2e678a1422b380324dd5f24", size = 106827, upload-time = "2025-06-19T17:12:42.994Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, ] [[package]] @@ -550,16 +610,16 @@ wheels = [ [[package]] name = "mkdocs-autorefs" -version = "1.4.2" +version = "1.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "markupsafe" }, { name = "mkdocs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/47/0c/c9826f35b99c67fa3a7cddfa094c1a6c43fafde558c309c6e4403e5b37dc/mkdocs_autorefs-1.4.2.tar.gz", hash = "sha256:e2ebe1abd2b67d597ed19378c0fff84d73d1dbce411fce7a7cc6f161888b6749", size = 54961, upload-time = "2025-05-20T13:09:09.886Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/fa/9124cd63d822e2bcbea1450ae68cdc3faf3655c69b455f3a7ed36ce6c628/mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75", size = 55425, upload-time = "2025-08-26T14:23:17.223Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/dc/fc063b78f4b769d1956319351704e23ebeba1e9e1d6a41b4b602325fd7e4/mkdocs_autorefs-1.4.2-py3-none-any.whl", hash = "sha256:83d6d777b66ec3c372a1aad4ae0cf77c243ba5bcda5bf0c6b8a2c5e7a3d89f13", size = 24969, upload-time = "2025-05-20T13:09:08.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4d/7123b6fa2278000688ebd338e2a06d16870aaf9eceae6ba047ea05f92df1/mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9", size = 25034, upload-time = "2025-08-26T14:23:15.906Z" }, ] [[package]] @@ -596,15 +656,15 @@ wheels = [ [[package]] name = "mkdocs-include-markdown-plugin" -version = "7.1.6" +version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mkdocs" }, { name = "wcmatch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/17/988d97ac6849b196f54d45ca9c60ca894880c160a512785f03834704b3d9/mkdocs_include_markdown_plugin-7.1.6.tar.gz", hash = "sha256:a0753cb82704c10a287f1e789fc9848f82b6beb8749814b24b03dd9f67816677", size = 23391, upload-time = "2025-06-13T18:25:51.193Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/10/b0b75ac42f4613556a808eee2dad3efe7a7d5079349aa5b9229d863e829f/mkdocs_include_markdown_plugin-7.2.0.tar.gz", hash = "sha256:4a67a91ade680dc0e15f608e5b6343bec03372ffa112c40a4254c1bfb10f42f3", size = 25509, upload-time = "2025-09-28T21:50:50.41Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/a1/6cf1667a05e5f468e1263fcf848772bca8cc9e358cd57ae19a01f92c9f6f/mkdocs_include_markdown_plugin-7.1.6-py3-none-any.whl", hash = "sha256:7975a593514887c18ecb68e11e35c074c5499cfa3e51b18cd16323862e1f7345", size = 27161, upload-time = "2025-06-13T18:25:49.847Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f9/783338d1d7fd548c7635728b67a0f8f96d9e6c265aa61c51356c03597767/mkdocs_include_markdown_plugin-7.2.0-py3-none-any.whl", hash = "sha256:d56cdaeb2d113fb66ed0fe4fb7af1da889926b0b9872032be24e19bbb09c9f5b", size = 29548, upload-time = "2025-09-28T21:50:49.373Z" }, ] [[package]] @@ -708,114 +768,114 @@ wheels = [ [[package]] name = "numpy" -version = "2.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/6d/745dd1c1c5c284d17725e5c802ca4d45cfc6803519d777f087b71c9f4069/numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b", size = 20956420, upload-time = "2025-07-24T20:28:18.002Z" }, - { url = "https://files.pythonhosted.org/packages/bc/96/e7b533ea5740641dd62b07a790af5d9d8fec36000b8e2d0472bd7574105f/numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f", size = 14184660, upload-time = "2025-07-24T20:28:39.522Z" }, - { url = "https://files.pythonhosted.org/packages/2b/53/102c6122db45a62aa20d1b18c9986f67e6b97e0d6fbc1ae13e3e4c84430c/numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0", size = 5113382, upload-time = "2025-07-24T20:28:48.544Z" }, - { url = "https://files.pythonhosted.org/packages/2b/21/376257efcbf63e624250717e82b4fae93d60178f09eb03ed766dbb48ec9c/numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b", size = 6647258, upload-time = "2025-07-24T20:28:59.104Z" }, - { url = "https://files.pythonhosted.org/packages/91/ba/f4ebf257f08affa464fe6036e13f2bf9d4642a40228781dc1235da81be9f/numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370", size = 14281409, upload-time = "2025-07-24T20:40:30.298Z" }, - { url = "https://files.pythonhosted.org/packages/59/ef/f96536f1df42c668cbacb727a8c6da7afc9c05ece6d558927fb1722693e1/numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73", size = 16641317, upload-time = "2025-07-24T20:40:56.625Z" }, - { url = "https://files.pythonhosted.org/packages/f6/a7/af813a7b4f9a42f498dde8a4c6fcbff8100eed00182cc91dbaf095645f38/numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc", size = 16056262, upload-time = "2025-07-24T20:41:20.797Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5d/41c4ef8404caaa7f05ed1cfb06afe16a25895260eacbd29b4d84dff2920b/numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be", size = 18579342, upload-time = "2025-07-24T20:41:50.753Z" }, - { url = "https://files.pythonhosted.org/packages/a1/4f/9950e44c5a11636f4a3af6e825ec23003475cc9a466edb7a759ed3ea63bd/numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036", size = 6320610, upload-time = "2025-07-24T20:42:01.551Z" }, - { url = "https://files.pythonhosted.org/packages/7c/2f/244643a5ce54a94f0a9a2ab578189c061e4a87c002e037b0829dd77293b6/numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f", size = 12786292, upload-time = "2025-07-24T20:42:20.738Z" }, - { url = "https://files.pythonhosted.org/packages/54/cd/7b5f49d5d78db7badab22d8323c1b6ae458fbf86c4fdfa194ab3cd4eb39b/numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07", size = 10194071, upload-time = "2025-07-24T20:42:36.657Z" }, - { url = "https://files.pythonhosted.org/packages/1c/c0/c6bb172c916b00700ed3bf71cb56175fd1f7dbecebf8353545d0b5519f6c/numpy-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c8d9727f5316a256425892b043736d63e89ed15bbfe6556c5ff4d9d4448ff3b3", size = 20949074, upload-time = "2025-07-24T20:43:07.813Z" }, - { url = "https://files.pythonhosted.org/packages/20/4e/c116466d22acaf4573e58421c956c6076dc526e24a6be0903219775d862e/numpy-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:efc81393f25f14d11c9d161e46e6ee348637c0a1e8a54bf9dedc472a3fae993b", size = 14177311, upload-time = "2025-07-24T20:43:29.335Z" }, - { url = "https://files.pythonhosted.org/packages/78/45/d4698c182895af189c463fc91d70805d455a227261d950e4e0f1310c2550/numpy-2.3.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dd937f088a2df683cbb79dda9a772b62a3e5a8a7e76690612c2737f38c6ef1b6", size = 5106022, upload-time = "2025-07-24T20:43:37.999Z" }, - { url = "https://files.pythonhosted.org/packages/9f/76/3e6880fef4420179309dba72a8c11f6166c431cf6dee54c577af8906f914/numpy-2.3.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:11e58218c0c46c80509186e460d79fbdc9ca1eb8d8aee39d8f2dc768eb781089", size = 6640135, upload-time = "2025-07-24T20:43:49.28Z" }, - { url = "https://files.pythonhosted.org/packages/34/fa/87ff7f25b3c4ce9085a62554460b7db686fef1e0207e8977795c7b7d7ba1/numpy-2.3.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5ad4ebcb683a1f99f4f392cc522ee20a18b2bb12a2c1c42c3d48d5a1adc9d3d2", size = 14278147, upload-time = "2025-07-24T20:44:10.328Z" }, - { url = "https://files.pythonhosted.org/packages/1d/0f/571b2c7a3833ae419fe69ff7b479a78d313581785203cc70a8db90121b9a/numpy-2.3.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:938065908d1d869c7d75d8ec45f735a034771c6ea07088867f713d1cd3bbbe4f", size = 16635989, upload-time = "2025-07-24T20:44:34.88Z" }, - { url = "https://files.pythonhosted.org/packages/24/5a/84ae8dca9c9a4c592fe11340b36a86ffa9fd3e40513198daf8a97839345c/numpy-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:66459dccc65d8ec98cc7df61307b64bf9e08101f9598755d42d8ae65d9a7a6ee", size = 16053052, upload-time = "2025-07-24T20:44:58.872Z" }, - { url = "https://files.pythonhosted.org/packages/57/7c/e5725d99a9133b9813fcf148d3f858df98511686e853169dbaf63aec6097/numpy-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a7af9ed2aa9ec5950daf05bb11abc4076a108bd3c7db9aa7251d5f107079b6a6", size = 18577955, upload-time = "2025-07-24T20:45:26.714Z" }, - { url = "https://files.pythonhosted.org/packages/ae/11/7c546fcf42145f29b71e4d6f429e96d8d68e5a7ba1830b2e68d7418f0bbd/numpy-2.3.2-cp313-cp313-win32.whl", hash = "sha256:906a30249315f9c8e17b085cc5f87d3f369b35fedd0051d4a84686967bdbbd0b", size = 6311843, upload-time = "2025-07-24T20:49:24.444Z" }, - { url = "https://files.pythonhosted.org/packages/aa/6f/a428fd1cb7ed39b4280d057720fed5121b0d7754fd2a9768640160f5517b/numpy-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:c63d95dc9d67b676e9108fe0d2182987ccb0f11933c1e8959f42fa0da8d4fa56", size = 12782876, upload-time = "2025-07-24T20:49:43.227Z" }, - { url = "https://files.pythonhosted.org/packages/65/85/4ea455c9040a12595fb6c43f2c217257c7b52dd0ba332c6a6c1d28b289fe/numpy-2.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:b05a89f2fb84d21235f93de47129dd4f11c16f64c87c33f5e284e6a3a54e43f2", size = 10192786, upload-time = "2025-07-24T20:49:59.443Z" }, - { url = "https://files.pythonhosted.org/packages/80/23/8278f40282d10c3f258ec3ff1b103d4994bcad78b0cba9208317f6bb73da/numpy-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e6ecfeddfa83b02318f4d84acf15fbdbf9ded18e46989a15a8b6995dfbf85ab", size = 21047395, upload-time = "2025-07-24T20:45:58.821Z" }, - { url = "https://files.pythonhosted.org/packages/1f/2d/624f2ce4a5df52628b4ccd16a4f9437b37c35f4f8a50d00e962aae6efd7a/numpy-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:508b0eada3eded10a3b55725b40806a4b855961040180028f52580c4729916a2", size = 14300374, upload-time = "2025-07-24T20:46:20.207Z" }, - { url = "https://files.pythonhosted.org/packages/f6/62/ff1e512cdbb829b80a6bd08318a58698867bca0ca2499d101b4af063ee97/numpy-2.3.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:754d6755d9a7588bdc6ac47dc4ee97867271b17cee39cb87aef079574366db0a", size = 5228864, upload-time = "2025-07-24T20:46:30.58Z" }, - { url = "https://files.pythonhosted.org/packages/7d/8e/74bc18078fff03192d4032cfa99d5a5ca937807136d6f5790ce07ca53515/numpy-2.3.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f66e7d2b2d7712410d3bc5684149040ef5f19856f20277cd17ea83e5006286", size = 6737533, upload-time = "2025-07-24T20:46:46.111Z" }, - { url = "https://files.pythonhosted.org/packages/19/ea/0731efe2c9073ccca5698ef6a8c3667c4cf4eea53fcdcd0b50140aba03bc/numpy-2.3.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6ea4e5a65d5a90c7d286ddff2b87f3f4ad61faa3db8dabe936b34c2275b6f8", size = 14352007, upload-time = "2025-07-24T20:47:07.1Z" }, - { url = "https://files.pythonhosted.org/packages/cf/90/36be0865f16dfed20f4bc7f75235b963d5939707d4b591f086777412ff7b/numpy-2.3.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3ef07ec8cbc8fc9e369c8dcd52019510c12da4de81367d8b20bc692aa07573a", size = 16701914, upload-time = "2025-07-24T20:47:32.459Z" }, - { url = "https://files.pythonhosted.org/packages/94/30/06cd055e24cb6c38e5989a9e747042b4e723535758e6153f11afea88c01b/numpy-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:27c9f90e7481275c7800dc9c24b7cc40ace3fdb970ae4d21eaff983a32f70c91", size = 16132708, upload-time = "2025-07-24T20:47:58.129Z" }, - { url = "https://files.pythonhosted.org/packages/9a/14/ecede608ea73e58267fd7cb78f42341b3b37ba576e778a1a06baffbe585c/numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5", size = 18651678, upload-time = "2025-07-24T20:48:25.402Z" }, - { url = "https://files.pythonhosted.org/packages/40/f3/2fe6066b8d07c3685509bc24d56386534c008b462a488b7f503ba82b8923/numpy-2.3.2-cp313-cp313t-win32.whl", hash = "sha256:c771cfac34a4f2c0de8e8c97312d07d64fd8f8ed45bc9f5726a7e947270152b5", size = 6441832, upload-time = "2025-07-24T20:48:37.181Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ba/0937d66d05204d8f28630c9c60bc3eda68824abde4cf756c4d6aad03b0c6/numpy-2.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:72dbebb2dcc8305c431b2836bcc66af967df91be793d63a24e3d9b741374c450", size = 12927049, upload-time = "2025-07-24T20:48:56.24Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ed/13542dd59c104d5e654dfa2ac282c199ba64846a74c2c4bcdbc3a0f75df1/numpy-2.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:72c6df2267e926a6d5286b0a6d556ebe49eae261062059317837fda12ddf0c1a", size = 10262935, upload-time = "2025-07-24T20:49:13.136Z" }, - { url = "https://files.pythonhosted.org/packages/c9/7c/7659048aaf498f7611b783e000c7268fcc4dcf0ce21cd10aad7b2e8f9591/numpy-2.3.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:448a66d052d0cf14ce9865d159bfc403282c9bc7bb2a31b03cc18b651eca8b1a", size = 20950906, upload-time = "2025-07-24T20:50:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/80/db/984bea9d4ddf7112a04cfdfb22b1050af5757864cfffe8e09e44b7f11a10/numpy-2.3.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:546aaf78e81b4081b2eba1d105c3b34064783027a06b3ab20b6eba21fb64132b", size = 14185607, upload-time = "2025-07-24T20:50:51.923Z" }, - { url = "https://files.pythonhosted.org/packages/e4/76/b3d6f414f4eca568f469ac112a3b510938d892bc5a6c190cb883af080b77/numpy-2.3.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:87c930d52f45df092f7578889711a0768094debf73cfcde105e2d66954358125", size = 5114110, upload-time = "2025-07-24T20:51:01.041Z" }, - { url = "https://files.pythonhosted.org/packages/9e/d2/6f5e6826abd6bca52392ed88fe44a4b52aacb60567ac3bc86c67834c3a56/numpy-2.3.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:8dc082ea901a62edb8f59713c6a7e28a85daddcb67454c839de57656478f5b19", size = 6642050, upload-time = "2025-07-24T20:51:11.64Z" }, - { url = "https://files.pythonhosted.org/packages/c4/43/f12b2ade99199e39c73ad182f103f9d9791f48d885c600c8e05927865baf/numpy-2.3.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af58de8745f7fa9ca1c0c7c943616c6fe28e75d0c81f5c295810e3c83b5be92f", size = 14296292, upload-time = "2025-07-24T20:51:33.488Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f9/77c07d94bf110a916b17210fac38680ed8734c236bfed9982fd8524a7b47/numpy-2.3.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed5527c4cf10f16c6d0b6bee1f89958bccb0ad2522c8cadc2efd318bcd545f5", size = 16638913, upload-time = "2025-07-24T20:51:58.517Z" }, - { url = "https://files.pythonhosted.org/packages/9b/d1/9d9f2c8ea399cc05cfff8a7437453bd4e7d894373a93cdc46361bbb49a7d/numpy-2.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:095737ed986e00393ec18ec0b21b47c22889ae4b0cd2d5e88342e08b01141f58", size = 16071180, upload-time = "2025-07-24T20:52:22.827Z" }, - { url = "https://files.pythonhosted.org/packages/4c/41/82e2c68aff2a0c9bf315e47d61951099fed65d8cb2c8d9dc388cb87e947e/numpy-2.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5e40e80299607f597e1a8a247ff8d71d79c5b52baa11cc1cce30aa92d2da6e0", size = 18576809, upload-time = "2025-07-24T20:52:51.015Z" }, - { url = "https://files.pythonhosted.org/packages/14/14/4b4fd3efb0837ed252d0f583c5c35a75121038a8c4e065f2c259be06d2d8/numpy-2.3.2-cp314-cp314-win32.whl", hash = "sha256:7d6e390423cc1f76e1b8108c9b6889d20a7a1f59d9a60cac4a050fa734d6c1e2", size = 6366410, upload-time = "2025-07-24T20:56:44.949Z" }, - { url = "https://files.pythonhosted.org/packages/11/9e/b4c24a6b8467b61aced5c8dc7dcfce23621baa2e17f661edb2444a418040/numpy-2.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:b9d0878b21e3918d76d2209c924ebb272340da1fb51abc00f986c258cd5e957b", size = 12918821, upload-time = "2025-07-24T20:57:06.479Z" }, - { url = "https://files.pythonhosted.org/packages/0e/0f/0dc44007c70b1007c1cef86b06986a3812dd7106d8f946c09cfa75782556/numpy-2.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:2738534837c6a1d0c39340a190177d7d66fdf432894f469728da901f8f6dc910", size = 10477303, upload-time = "2025-07-24T20:57:22.879Z" }, - { url = "https://files.pythonhosted.org/packages/8b/3e/075752b79140b78ddfc9c0a1634d234cfdbc6f9bbbfa6b7504e445ad7d19/numpy-2.3.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4d002ecf7c9b53240be3bb69d80f86ddbd34078bae04d87be81c1f58466f264e", size = 21047524, upload-time = "2025-07-24T20:53:22.086Z" }, - { url = "https://files.pythonhosted.org/packages/fe/6d/60e8247564a72426570d0e0ea1151b95ce5bd2f1597bb878a18d32aec855/numpy-2.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:293b2192c6bcce487dbc6326de5853787f870aeb6c43f8f9c6496db5b1781e45", size = 14300519, upload-time = "2025-07-24T20:53:44.053Z" }, - { url = "https://files.pythonhosted.org/packages/4d/73/d8326c442cd428d47a067070c3ac6cc3b651a6e53613a1668342a12d4479/numpy-2.3.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0a4f2021a6da53a0d580d6ef5db29947025ae8b35b3250141805ea9a32bbe86b", size = 5228972, upload-time = "2025-07-24T20:53:53.81Z" }, - { url = "https://files.pythonhosted.org/packages/34/2e/e71b2d6dad075271e7079db776196829019b90ce3ece5c69639e4f6fdc44/numpy-2.3.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9c144440db4bf3bb6372d2c3e49834cc0ff7bb4c24975ab33e01199e645416f2", size = 6737439, upload-time = "2025-07-24T20:54:04.742Z" }, - { url = "https://files.pythonhosted.org/packages/15/b0/d004bcd56c2c5e0500ffc65385eb6d569ffd3363cb5e593ae742749b2daa/numpy-2.3.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f92d6c2a8535dc4fe4419562294ff957f83a16ebdec66df0805e473ffaad8bd0", size = 14352479, upload-time = "2025-07-24T20:54:25.819Z" }, - { url = "https://files.pythonhosted.org/packages/11/e3/285142fcff8721e0c99b51686426165059874c150ea9ab898e12a492e291/numpy-2.3.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cefc2219baa48e468e3db7e706305fcd0c095534a192a08f31e98d83a7d45fb0", size = 16702805, upload-time = "2025-07-24T20:54:50.814Z" }, - { url = "https://files.pythonhosted.org/packages/33/c3/33b56b0e47e604af2c7cd065edca892d180f5899599b76830652875249a3/numpy-2.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:76c3e9501ceb50b2ff3824c3589d5d1ab4ac857b0ee3f8f49629d0de55ecf7c2", size = 16133830, upload-time = "2025-07-24T20:55:17.306Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ae/7b1476a1f4d6a48bc669b8deb09939c56dd2a439db1ab03017844374fb67/numpy-2.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:122bf5ed9a0221b3419672493878ba4967121514b1d7d4656a7580cd11dddcbf", size = 18652665, upload-time = "2025-07-24T20:55:46.665Z" }, - { url = "https://files.pythonhosted.org/packages/14/ba/5b5c9978c4bb161034148ade2de9db44ec316fab89ce8c400db0e0c81f86/numpy-2.3.2-cp314-cp314t-win32.whl", hash = "sha256:6f1ae3dcb840edccc45af496f312528c15b1f79ac318169d094e85e4bb35fdf1", size = 6514777, upload-time = "2025-07-24T20:55:57.66Z" }, - { url = "https://files.pythonhosted.org/packages/eb/46/3dbaf0ae7c17cdc46b9f662c56da2054887b8d9e737c1476f335c83d33db/numpy-2.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b", size = 13111856, upload-time = "2025-07-24T20:56:17.318Z" }, - { url = "https://files.pythonhosted.org/packages/c1/9e/1652778bce745a67b5fe05adde60ed362d38eb17d919a540e813d30f6874/numpy-2.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:092aeb3449833ea9c0bf0089d70c29ae480685dd2377ec9cdbbb620257f84631", size = 10544226, upload-time = "2025-07-24T20:56:34.509Z" }, +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" }, + { url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" }, + { url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" }, + { url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" }, + { url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" }, + { url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" }, + { url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" }, + { url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" }, + { url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" }, + { url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" }, + { url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" }, + { url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" }, + { url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" }, + { url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" }, + { url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" }, + { url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" }, + { url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" }, + { url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" }, + { url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" }, + { url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" }, + { url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" }, + { url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" }, + { url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" }, + { url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" }, + { url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" }, + { url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" }, + { url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" }, + { url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" }, + { url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" }, ] [[package]] name = "orjson" -version = "3.11.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/1d/5e0ae38788bdf0721326695e65fdf41405ed535f633eb0df0f06f57552fa/orjson-3.11.2.tar.gz", hash = "sha256:91bdcf5e69a8fd8e8bdb3de32b31ff01d2bd60c1e8d5fe7d5afabdcf19920309", size = 5470739, upload-time = "2025-08-12T15:12:28.626Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/02/46054ebe7996a8adee9640dcad7d39d76c2000dc0377efa38e55dc5cbf78/orjson-3.11.2-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:901d80d349d8452162b3aa1afb82cec5bee79a10550660bc21311cc61a4c5486", size = 226528, upload-time = "2025-08-12T15:11:03.317Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/6b6f0b4d8aea1137436546b990f71be2cd8bd870aa2f5aa14dba0fcc95dc/orjson-3.11.2-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:cf3bd3967a360e87ee14ed82cb258b7f18c710dacf3822fb0042a14313a673a1", size = 115931, upload-time = "2025-08-12T15:11:04.759Z" }, - { url = "https://files.pythonhosted.org/packages/ae/05/4205cc97c30e82a293dd0d149b1a89b138ebe76afeca66fc129fa2aa4e6a/orjson-3.11.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26693dde66910078229a943e80eeb99fdce6cd2c26277dc80ead9f3ab97d2131", size = 111382, upload-time = "2025-08-12T15:11:06.468Z" }, - { url = "https://files.pythonhosted.org/packages/50/c7/b8a951a93caa821f9272a7c917115d825ae2e4e8768f5ddf37968ec9de01/orjson-3.11.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad4c8acb50a28211c33fc7ef85ddf5cb18d4636a5205fd3fa2dce0411a0e30c", size = 116271, upload-time = "2025-08-12T15:11:07.845Z" }, - { url = "https://files.pythonhosted.org/packages/17/03/1006c7f8782d5327439e26d9b0ec66500ea7b679d4bbb6b891d2834ab3ee/orjson-3.11.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:994181e7f1725bb5f2d481d7d228738e0743b16bf319ca85c29369c65913df14", size = 119086, upload-time = "2025-08-12T15:11:09.329Z" }, - { url = "https://files.pythonhosted.org/packages/44/61/57d22bc31f36a93878a6f772aea76b2184102c6993dea897656a66d18c74/orjson-3.11.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbb79a0476393c07656b69c8e763c3cc925fa8e1d9e9b7d1f626901bb5025448", size = 120724, upload-time = "2025-08-12T15:11:10.674Z" }, - { url = "https://files.pythonhosted.org/packages/78/a9/4550e96b4c490c83aea697d5347b8f7eb188152cd7b5a38001055ca5b379/orjson-3.11.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:191ed27a1dddb305083d8716af413d7219f40ec1d4c9b0e977453b4db0d6fb6c", size = 123577, upload-time = "2025-08-12T15:11:12.015Z" }, - { url = "https://files.pythonhosted.org/packages/3a/86/09b8cb3ebd513d708ef0c92d36ac3eebda814c65c72137b0a82d6d688fc4/orjson-3.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0afb89f16f07220183fd00f5f297328ed0a68d8722ad1b0c8dcd95b12bc82804", size = 121195, upload-time = "2025-08-12T15:11:13.399Z" }, - { url = "https://files.pythonhosted.org/packages/37/68/7b40b39ac2c1c644d4644e706d0de6c9999764341cd85f2a9393cb387661/orjson-3.11.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ab6e6b4e93b1573a026b6ec16fca9541354dd58e514b62c558b58554ae04307", size = 119234, upload-time = "2025-08-12T15:11:15.134Z" }, - { url = "https://files.pythonhosted.org/packages/40/7c/bb6e7267cd80c19023d44d8cbc4ea4ed5429fcd4a7eb9950f50305697a28/orjson-3.11.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9cb23527efb61fb75527df55d20ee47989c4ee34e01a9c98ee9ede232abf6219", size = 392250, upload-time = "2025-08-12T15:11:16.604Z" }, - { url = "https://files.pythonhosted.org/packages/64/f2/6730ace05583dbca7c1b406d59f4266e48cd0d360566e71482420fb849fc/orjson-3.11.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a4dd1268e4035af21b8a09e4adf2e61f87ee7bf63b86d7bb0a237ac03fad5b45", size = 134572, upload-time = "2025-08-12T15:11:18.205Z" }, - { url = "https://files.pythonhosted.org/packages/96/0f/7d3e03a30d5aac0432882b539a65b8c02cb6dd4221ddb893babf09c424cc/orjson-3.11.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff8b155b145eaf5a9d94d2c476fbe18d6021de93cf36c2ae2c8c5b775763f14e", size = 123869, upload-time = "2025-08-12T15:11:19.554Z" }, - { url = "https://files.pythonhosted.org/packages/45/80/1513265eba6d4a960f078f4b1d2bff94a571ab2d28c6f9835e03dfc65cc6/orjson-3.11.2-cp312-cp312-win32.whl", hash = "sha256:ae3bb10279d57872f9aba68c9931aa71ed3b295fa880f25e68da79e79453f46e", size = 124430, upload-time = "2025-08-12T15:11:20.914Z" }, - { url = "https://files.pythonhosted.org/packages/fb/61/eadf057b68a332351eeb3d89a4cc538d14f31cd8b5ec1b31a280426ccca2/orjson-3.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:d026e1967239ec11a2559b4146a61d13914504b396f74510a1c4d6b19dfd8732", size = 119598, upload-time = "2025-08-12T15:11:22.372Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3f/7f4b783402143d965ab7e9a2fc116fdb887fe53bdce7d3523271cd106098/orjson-3.11.2-cp312-cp312-win_arm64.whl", hash = "sha256:59f8d5ad08602711af9589375be98477d70e1d102645430b5a7985fdbf613b36", size = 114052, upload-time = "2025-08-12T15:11:23.762Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f3/0dd6b4750eb556ae4e2c6a9cb3e219ec642e9c6d95f8ebe5dc9020c67204/orjson-3.11.2-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a079fdba7062ab396380eeedb589afb81dc6683f07f528a03b6f7aae420a0219", size = 226419, upload-time = "2025-08-12T15:11:25.517Z" }, - { url = "https://files.pythonhosted.org/packages/44/d5/e67f36277f78f2af8a4690e0c54da6b34169812f807fd1b4bfc4dbcf9558/orjson-3.11.2-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:6a5f62ebbc530bb8bb4b1ead103647b395ba523559149b91a6c545f7cd4110ad", size = 115803, upload-time = "2025-08-12T15:11:27.357Z" }, - { url = "https://files.pythonhosted.org/packages/24/37/ff8bc86e0dacc48f07c2b6e20852f230bf4435611bab65e3feae2b61f0ae/orjson-3.11.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7df6c7b8b0931feb3420b72838c3e2ba98c228f7aa60d461bc050cf4ca5f7b2", size = 111337, upload-time = "2025-08-12T15:11:28.805Z" }, - { url = "https://files.pythonhosted.org/packages/b9/25/37d4d3e8079ea9784ea1625029988e7f4594ce50d4738b0c1e2bf4a9e201/orjson-3.11.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6f59dfea7da1fced6e782bb3699718088b1036cb361f36c6e4dd843c5111aefe", size = 116222, upload-time = "2025-08-12T15:11:30.18Z" }, - { url = "https://files.pythonhosted.org/packages/b7/32/a63fd9c07fce3b4193dcc1afced5dd4b0f3a24e27556604e9482b32189c9/orjson-3.11.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edf49146520fef308c31aa4c45b9925fd9c7584645caca7c0c4217d7900214ae", size = 119020, upload-time = "2025-08-12T15:11:31.59Z" }, - { url = "https://files.pythonhosted.org/packages/b4/b6/400792b8adc3079a6b5d649264a3224d6342436d9fac9a0ed4abc9dc4596/orjson-3.11.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50995bbeb5d41a32ad15e023305807f561ac5dcd9bd41a12c8d8d1d2c83e44e6", size = 120721, upload-time = "2025-08-12T15:11:33.035Z" }, - { url = "https://files.pythonhosted.org/packages/40/f3/31ab8f8c699eb9e65af8907889a0b7fef74c1d2b23832719a35da7bb0c58/orjson-3.11.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cc42960515076eb639b705f105712b658c525863d89a1704d984b929b0577d1", size = 123574, upload-time = "2025-08-12T15:11:34.433Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a6/ce4287c412dff81878f38d06d2c80845709c60012ca8daf861cb064b4574/orjson-3.11.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56777cab2a7b2a8ea687fedafb84b3d7fdafae382165c31a2adf88634c432fa", size = 121225, upload-time = "2025-08-12T15:11:36.133Z" }, - { url = "https://files.pythonhosted.org/packages/69/b0/7a881b2aef4fed0287d2a4fbb029d01ed84fa52b4a68da82bdee5e50598e/orjson-3.11.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07349e88025b9b5c783077bf7a9f401ffbfb07fd20e86ec6fc5b7432c28c2c5e", size = 119201, upload-time = "2025-08-12T15:11:37.642Z" }, - { url = "https://files.pythonhosted.org/packages/cf/98/a325726b37f7512ed6338e5e65035c3c6505f4e628b09a5daf0419f054ea/orjson-3.11.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:45841fbb79c96441a8c58aa29ffef570c5df9af91f0f7a9572e5505e12412f15", size = 392193, upload-time = "2025-08-12T15:11:39.153Z" }, - { url = "https://files.pythonhosted.org/packages/cb/4f/a7194f98b0ce1d28190e0c4caa6d091a3fc8d0107ad2209f75c8ba398984/orjson-3.11.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:13d8d8db6cd8d89d4d4e0f4161acbbb373a4d2a4929e862d1d2119de4aa324ac", size = 134548, upload-time = "2025-08-12T15:11:40.768Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/b84caa2986c3f472dc56343ddb0167797a708a8d5c3be043e1e2677b55df/orjson-3.11.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51da1ee2178ed09c00d09c1b953e45846bbc16b6420965eb7a913ba209f606d8", size = 123798, upload-time = "2025-08-12T15:11:42.164Z" }, - { url = "https://files.pythonhosted.org/packages/9c/5b/e398449080ce6b4c8fcadad57e51fa16f65768e1b142ba90b23ac5d10801/orjson-3.11.2-cp313-cp313-win32.whl", hash = "sha256:51dc033df2e4a4c91c0ba4f43247de99b3cbf42ee7a42ee2b2b2f76c8b2f2cb5", size = 124402, upload-time = "2025-08-12T15:11:44.036Z" }, - { url = "https://files.pythonhosted.org/packages/b3/66/429e4608e124debfc4790bfc37131f6958e59510ba3b542d5fc163be8e5f/orjson-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:29d91d74942b7436f29b5d1ed9bcfc3f6ef2d4f7c4997616509004679936650d", size = 119498, upload-time = "2025-08-12T15:11:45.864Z" }, - { url = "https://files.pythonhosted.org/packages/7b/04/f8b5f317cce7ad3580a9ad12d7e2df0714dfa8a83328ecddd367af802f5b/orjson-3.11.2-cp313-cp313-win_arm64.whl", hash = "sha256:4ca4fb5ac21cd1e48028d4f708b1bb13e39c42d45614befd2ead004a8bba8535", size = 114051, upload-time = "2025-08-12T15:11:47.555Z" }, - { url = "https://files.pythonhosted.org/packages/74/83/2c363022b26c3c25b3708051a19d12f3374739bb81323f05b284392080c0/orjson-3.11.2-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3dcba7101ea6a8d4ef060746c0f2e7aa8e2453a1012083e1ecce9726d7554cb7", size = 226406, upload-time = "2025-08-12T15:11:49.445Z" }, - { url = "https://files.pythonhosted.org/packages/b0/a7/aa3c973de0b33fc93b4bd71691665ffdfeae589ea9d0625584ab10a7d0f5/orjson-3.11.2-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:15d17bdb76a142e1f55d91913e012e6e6769659daa6bfef3ef93f11083137e81", size = 115788, upload-time = "2025-08-12T15:11:50.992Z" }, - { url = "https://files.pythonhosted.org/packages/ef/f2/e45f233dfd09fdbb052ec46352363dca3906618e1a2b264959c18f809d0b/orjson-3.11.2-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:53c9e81768c69d4b66b8876ec3c8e431c6e13477186d0db1089d82622bccd19f", size = 111318, upload-time = "2025-08-12T15:11:52.495Z" }, - { url = "https://files.pythonhosted.org/packages/3e/23/cf5a73c4da6987204cbbf93167f353ff0c5013f7c5e5ef845d4663a366da/orjson-3.11.2-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d4f13af59a7b84c1ca6b8a7ab70d608f61f7c44f9740cd42409e6ae7b6c8d8b7", size = 121231, upload-time = "2025-08-12T15:11:53.941Z" }, - { url = "https://files.pythonhosted.org/packages/40/1d/47468a398ae68a60cc21e599144e786e035bb12829cb587299ecebc088f1/orjson-3.11.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bde64aa469b5ee46cc960ed241fae3721d6a8801dacb2ca3466547a2535951e4", size = 119204, upload-time = "2025-08-12T15:11:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d9/f99433d89b288b5bc8836bffb32a643f805e673cf840ef8bab6e73ced0d1/orjson-3.11.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b5ca86300aeb383c8fa759566aca065878d3d98c3389d769b43f0a2e84d52c5f", size = 392237, upload-time = "2025-08-12T15:11:57.18Z" }, - { url = "https://files.pythonhosted.org/packages/d4/dc/1b9d80d40cebef603325623405136a29fb7d08c877a728c0943dd066c29a/orjson-3.11.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:24e32a558ebed73a6a71c8f1cbc163a7dd5132da5270ff3d8eeb727f4b6d1bc7", size = 134578, upload-time = "2025-08-12T15:11:58.844Z" }, - { url = "https://files.pythonhosted.org/packages/45/b3/72e7a4c5b6485ef4e83ef6aba7f1dd041002bad3eb5d1d106ca5b0fc02c6/orjson-3.11.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e36319a5d15b97e4344110517450396845cc6789aed712b1fbf83c1bd95792f6", size = 123799, upload-time = "2025-08-12T15:12:00.352Z" }, - { url = "https://files.pythonhosted.org/packages/c8/3e/a3d76b392e7acf9b34dc277171aad85efd6accc75089bb35b4c614990ea9/orjson-3.11.2-cp314-cp314-win32.whl", hash = "sha256:40193ada63fab25e35703454d65b6afc71dbc65f20041cb46c6d91709141ef7f", size = 124461, upload-time = "2025-08-12T15:12:01.854Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/75c6a596ff8df9e4a5894813ff56695f0a218e6ea99420b4a645c4f7795d/orjson-3.11.2-cp314-cp314-win_amd64.whl", hash = "sha256:7c8ac5f6b682d3494217085cf04dadae66efee45349ad4ee2a1da3c97e2305a8", size = 119494, upload-time = "2025-08-12T15:12:03.337Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3d/9e74742fc261c5ca473c96bb3344d03995869e1dc6402772c60afb97736a/orjson-3.11.2-cp314-cp314-win_arm64.whl", hash = "sha256:21cf261e8e79284242e4cb1e5924df16ae28255184aafeff19be1405f6d33f67", size = 114046, upload-time = "2025-08-12T15:12:04.87Z" }, +version = "3.11.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/4d/8df5f83256a809c22c4d6792ce8d43bb503be0fb7a8e4da9025754b09658/orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a", size = 5482394, upload-time = "2025-08-26T17:46:43.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/b0/a7edab2a00cdcb2688e1c943401cb3236323e7bfd2839815c6131a3742f4/orjson-3.11.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b", size = 238259, upload-time = "2025-08-26T17:45:15.093Z" }, + { url = "https://files.pythonhosted.org/packages/e1/c6/ff4865a9cc398a07a83342713b5932e4dc3cb4bf4bc04e8f83dedfc0d736/orjson-3.11.3-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2", size = 127633, upload-time = "2025-08-26T17:45:16.417Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e6/e00bea2d9472f44fe8794f523e548ce0ad51eb9693cf538a753a27b8bda4/orjson-3.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a", size = 123061, upload-time = "2025-08-26T17:45:17.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/31/9fbb78b8e1eb3ac605467cb846e1c08d0588506028b37f4ee21f978a51d4/orjson-3.11.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c", size = 127956, upload-time = "2025-08-26T17:45:19.172Z" }, + { url = "https://files.pythonhosted.org/packages/36/88/b0604c22af1eed9f98d709a96302006915cfd724a7ebd27d6dd11c22d80b/orjson-3.11.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064", size = 130790, upload-time = "2025-08-26T17:45:20.586Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9d/1c1238ae9fffbfed51ba1e507731b3faaf6b846126a47e9649222b0fd06f/orjson-3.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424", size = 132385, upload-time = "2025-08-26T17:45:22.036Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b5/c06f1b090a1c875f337e21dd71943bc9d84087f7cdf8c6e9086902c34e42/orjson-3.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23", size = 135305, upload-time = "2025-08-26T17:45:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/a0/26/5f028c7d81ad2ebbf84414ba6d6c9cac03f22f5cd0d01eb40fb2d6a06b07/orjson-3.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667", size = 132875, upload-time = "2025-08-26T17:45:25.182Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d4/b8df70d9cfb56e385bf39b4e915298f9ae6c61454c8154a0f5fd7efcd42e/orjson-3.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f", size = 130940, upload-time = "2025-08-26T17:45:27.209Z" }, + { url = "https://files.pythonhosted.org/packages/da/5e/afe6a052ebc1a4741c792dd96e9f65bf3939d2094e8b356503b68d48f9f5/orjson-3.11.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1", size = 403852, upload-time = "2025-08-26T17:45:28.478Z" }, + { url = "https://files.pythonhosted.org/packages/f8/90/7bbabafeb2ce65915e9247f14a56b29c9334003536009ef5b122783fe67e/orjson-3.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc", size = 146293, upload-time = "2025-08-26T17:45:29.86Z" }, + { url = "https://files.pythonhosted.org/packages/27/b3/2d703946447da8b093350570644a663df69448c9d9330e5f1d9cce997f20/orjson-3.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049", size = 135470, upload-time = "2025-08-26T17:45:31.243Z" }, + { url = "https://files.pythonhosted.org/packages/38/70/b14dcfae7aff0e379b0119c8a812f8396678919c431efccc8e8a0263e4d9/orjson-3.11.3-cp312-cp312-win32.whl", hash = "sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca", size = 136248, upload-time = "2025-08-26T17:45:32.567Z" }, + { url = "https://files.pythonhosted.org/packages/35/b8/9e3127d65de7fff243f7f3e53f59a531bf6bb295ebe5db024c2503cc0726/orjson-3.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1", size = 131437, upload-time = "2025-08-26T17:45:34.949Z" }, + { url = "https://files.pythonhosted.org/packages/51/92/a946e737d4d8a7fd84a606aba96220043dcc7d6988b9e7551f7f6d5ba5ad/orjson-3.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710", size = 125978, upload-time = "2025-08-26T17:45:36.422Z" }, + { url = "https://files.pythonhosted.org/packages/fc/79/8932b27293ad35919571f77cb3693b5906cf14f206ef17546052a241fdf6/orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810", size = 238127, upload-time = "2025-08-26T17:45:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/1c/82/cb93cd8cf132cd7643b30b6c5a56a26c4e780c7a145db6f83de977b540ce/orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43", size = 127494, upload-time = "2025-08-26T17:45:39.57Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/2d9eb181a9b6bb71463a78882bcac1027fd29cf62c38a40cc02fc11d3495/orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27", size = 123017, upload-time = "2025-08-26T17:45:40.876Z" }, + { url = "https://files.pythonhosted.org/packages/b4/14/a0e971e72d03b509190232356d54c0f34507a05050bd026b8db2bf2c192c/orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f", size = 127898, upload-time = "2025-08-26T17:45:42.188Z" }, + { url = "https://files.pythonhosted.org/packages/8e/af/dc74536722b03d65e17042cc30ae586161093e5b1f29bccda24765a6ae47/orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c", size = 130742, upload-time = "2025-08-26T17:45:43.511Z" }, + { url = "https://files.pythonhosted.org/packages/62/e6/7a3b63b6677bce089fe939353cda24a7679825c43a24e49f757805fc0d8a/orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be", size = 132377, upload-time = "2025-08-26T17:45:45.525Z" }, + { url = "https://files.pythonhosted.org/packages/fc/cd/ce2ab93e2e7eaf518f0fd15e3068b8c43216c8a44ed82ac2b79ce5cef72d/orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d", size = 135313, upload-time = "2025-08-26T17:45:46.821Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/f98355eff0bd1a38454209bbc73372ce351ba29933cb3e2eba16c04b9448/orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2", size = 132908, upload-time = "2025-08-26T17:45:48.126Z" }, + { url = "https://files.pythonhosted.org/packages/eb/92/8f5182d7bc2a1bed46ed960b61a39af8389f0ad476120cd99e67182bfb6d/orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f", size = 130905, upload-time = "2025-08-26T17:45:49.414Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/c41ca753ce9ffe3d0f67b9b4c093bdd6e5fdb1bc53064f992f66bb99954d/orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee", size = 403812, upload-time = "2025-08-26T17:45:51.085Z" }, + { url = "https://files.pythonhosted.org/packages/dd/13/e4a4f16d71ce1868860db59092e78782c67082a8f1dc06a3788aef2b41bc/orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e", size = 146277, upload-time = "2025-08-26T17:45:52.851Z" }, + { url = "https://files.pythonhosted.org/packages/8d/8b/bafb7f0afef9344754a3a0597a12442f1b85a048b82108ef2c956f53babd/orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633", size = 135418, upload-time = "2025-08-26T17:45:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/60/d4/bae8e4f26afb2c23bea69d2f6d566132584d1c3a5fe89ee8c17b718cab67/orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b", size = 136216, upload-time = "2025-08-26T17:45:57.182Z" }, + { url = "https://files.pythonhosted.org/packages/88/76/224985d9f127e121c8cad882cea55f0ebe39f97925de040b75ccd4b33999/orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae", size = 131362, upload-time = "2025-08-26T17:45:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cf/0dce7a0be94bd36d1346be5067ed65ded6adb795fdbe3abd234c8d576d01/orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce", size = 125989, upload-time = "2025-08-26T17:45:59.95Z" }, + { url = "https://files.pythonhosted.org/packages/ef/77/d3b1fef1fc6aaeed4cbf3be2b480114035f4df8fa1a99d2dac1d40d6e924/orjson-3.11.3-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4", size = 238115, upload-time = "2025-08-26T17:46:01.669Z" }, + { url = "https://files.pythonhosted.org/packages/e4/6d/468d21d49bb12f900052edcfbf52c292022d0a323d7828dc6376e6319703/orjson-3.11.3-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e", size = 127493, upload-time = "2025-08-26T17:46:03.466Z" }, + { url = "https://files.pythonhosted.org/packages/67/46/1e2588700d354aacdf9e12cc2d98131fb8ac6f31ca65997bef3863edb8ff/orjson-3.11.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d", size = 122998, upload-time = "2025-08-26T17:46:04.803Z" }, + { url = "https://files.pythonhosted.org/packages/3b/94/11137c9b6adb3779f1b34fd98be51608a14b430dbc02c6d41134fbba484c/orjson-3.11.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229", size = 132915, upload-time = "2025-08-26T17:46:06.237Z" }, + { url = "https://files.pythonhosted.org/packages/10/61/dccedcf9e9bcaac09fdabe9eaee0311ca92115699500efbd31950d878833/orjson-3.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451", size = 130907, upload-time = "2025-08-26T17:46:07.581Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fd/0e935539aa7b08b3ca0f817d73034f7eb506792aae5ecc3b7c6e679cdf5f/orjson-3.11.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167", size = 403852, upload-time = "2025-08-26T17:46:08.982Z" }, + { url = "https://files.pythonhosted.org/packages/4a/2b/50ae1a5505cd1043379132fdb2adb8a05f37b3e1ebffe94a5073321966fd/orjson-3.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077", size = 146309, upload-time = "2025-08-26T17:46:10.576Z" }, + { url = "https://files.pythonhosted.org/packages/cd/1d/a473c158e380ef6f32753b5f39a69028b25ec5be331c2049a2201bde2e19/orjson-3.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872", size = 135424, upload-time = "2025-08-26T17:46:12.386Z" }, + { url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" }, + { url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" }, ] [[package]] @@ -881,11 +941,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, ] [[package]] @@ -1044,7 +1104,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.4.1" +version = "8.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1053,9 +1113,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] [[package]] @@ -1137,40 +1197,65 @@ wheels = [ [[package]] name = "rapidfuzz" -version = "3.13.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/f6/6895abc3a3d056b9698da3199b04c0e56226d530ae44a470edabf8b664f0/rapidfuzz-3.13.0.tar.gz", hash = "sha256:d2eaf3839e52cbcc0accbe9817a67b4b0fcf70aaeb229cfddc1c28061f9ce5d8", size = 57904226, upload-time = "2025-04-03T20:38:51.226Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/4b/a326f57a4efed8f5505b25102797a58e37ee11d94afd9d9422cb7c76117e/rapidfuzz-3.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a1a6a906ba62f2556372282b1ef37b26bca67e3d2ea957277cfcefc6275cca7", size = 1989501, upload-time = "2025-04-03T20:36:13.43Z" }, - { url = "https://files.pythonhosted.org/packages/b7/53/1f7eb7ee83a06c400089ec7cb841cbd581c2edd7a4b21eb2f31030b88daa/rapidfuzz-3.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fd0975e015b05c79a97f38883a11236f5a24cca83aa992bd2558ceaa5652b26", size = 1445379, upload-time = "2025-04-03T20:36:16.439Z" }, - { url = "https://files.pythonhosted.org/packages/07/09/de8069a4599cc8e6d194e5fa1782c561151dea7d5e2741767137e2a8c1f0/rapidfuzz-3.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d4e13593d298c50c4f94ce453f757b4b398af3fa0fd2fde693c3e51195b7f69", size = 1405986, upload-time = "2025-04-03T20:36:18.447Z" }, - { url = "https://files.pythonhosted.org/packages/5d/77/d9a90b39c16eca20d70fec4ca377fbe9ea4c0d358c6e4736ab0e0e78aaf6/rapidfuzz-3.13.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed6f416bda1c9133000009d84d9409823eb2358df0950231cc936e4bf784eb97", size = 5310809, upload-time = "2025-04-03T20:36:20.324Z" }, - { url = "https://files.pythonhosted.org/packages/1e/7d/14da291b0d0f22262d19522afaf63bccf39fc027c981233fb2137a57b71f/rapidfuzz-3.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1dc82b6ed01acb536b94a43996a94471a218f4d89f3fdd9185ab496de4b2a981", size = 1629394, upload-time = "2025-04-03T20:36:22.256Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e4/79ed7e4fa58f37c0f8b7c0a62361f7089b221fe85738ae2dbcfb815e985a/rapidfuzz-3.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9d824de871daa6e443b39ff495a884931970d567eb0dfa213d234337343835f", size = 1600544, upload-time = "2025-04-03T20:36:24.207Z" }, - { url = "https://files.pythonhosted.org/packages/4e/20/e62b4d13ba851b0f36370060025de50a264d625f6b4c32899085ed51f980/rapidfuzz-3.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d18228a2390375cf45726ce1af9d36ff3dc1f11dce9775eae1f1b13ac6ec50f", size = 3052796, upload-time = "2025-04-03T20:36:26.279Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8d/55fdf4387dec10aa177fe3df8dbb0d5022224d95f48664a21d6b62a5299d/rapidfuzz-3.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5fe634c9482ec5d4a6692afb8c45d370ae86755e5f57aa6c50bfe4ca2bdd87", size = 2464016, upload-time = "2025-04-03T20:36:28.525Z" }, - { url = "https://files.pythonhosted.org/packages/9b/be/0872f6a56c0f473165d3b47d4170fa75263dc5f46985755aa9bf2bbcdea1/rapidfuzz-3.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:694eb531889f71022b2be86f625a4209c4049e74be9ca836919b9e395d5e33b3", size = 7556725, upload-time = "2025-04-03T20:36:30.629Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f3/6c0750e484d885a14840c7a150926f425d524982aca989cdda0bb3bdfa57/rapidfuzz-3.13.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:11b47b40650e06147dee5e51a9c9ad73bb7b86968b6f7d30e503b9f8dd1292db", size = 2859052, upload-time = "2025-04-03T20:36:32.836Z" }, - { url = "https://files.pythonhosted.org/packages/6f/98/5a3a14701b5eb330f444f7883c9840b43fb29c575e292e09c90a270a6e07/rapidfuzz-3.13.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:98b8107ff14f5af0243f27d236bcc6e1ef8e7e3b3c25df114e91e3a99572da73", size = 3390219, upload-time = "2025-04-03T20:36:35.062Z" }, - { url = "https://files.pythonhosted.org/packages/e9/7d/f4642eaaeb474b19974332f2a58471803448be843033e5740965775760a5/rapidfuzz-3.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b836f486dba0aceb2551e838ff3f514a38ee72b015364f739e526d720fdb823a", size = 4377924, upload-time = "2025-04-03T20:36:37.363Z" }, - { url = "https://files.pythonhosted.org/packages/8e/83/fa33f61796731891c3e045d0cbca4436a5c436a170e7f04d42c2423652c3/rapidfuzz-3.13.0-cp312-cp312-win32.whl", hash = "sha256:4671ee300d1818d7bdfd8fa0608580d7778ba701817216f0c17fb29e6b972514", size = 1823915, upload-time = "2025-04-03T20:36:39.451Z" }, - { url = "https://files.pythonhosted.org/packages/03/25/5ee7ab6841ca668567d0897905eebc79c76f6297b73bf05957be887e9c74/rapidfuzz-3.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e2065f68fb1d0bf65adc289c1bdc45ba7e464e406b319d67bb54441a1b9da9e", size = 1616985, upload-time = "2025-04-03T20:36:41.631Z" }, - { url = "https://files.pythonhosted.org/packages/76/5e/3f0fb88db396cb692aefd631e4805854e02120a2382723b90dcae720bcc6/rapidfuzz-3.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:65cc97c2fc2c2fe23586599686f3b1ceeedeca8e598cfcc1b7e56dc8ca7e2aa7", size = 860116, upload-time = "2025-04-03T20:36:43.915Z" }, - { url = "https://files.pythonhosted.org/packages/0a/76/606e71e4227790750f1646f3c5c873e18d6cfeb6f9a77b2b8c4dec8f0f66/rapidfuzz-3.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:09e908064d3684c541d312bd4c7b05acb99a2c764f6231bd507d4b4b65226c23", size = 1982282, upload-time = "2025-04-03T20:36:46.149Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f5/d0b48c6b902607a59fd5932a54e3518dae8223814db8349b0176e6e9444b/rapidfuzz-3.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57c390336cb50d5d3bfb0cfe1467478a15733703af61f6dffb14b1cd312a6fae", size = 1439274, upload-time = "2025-04-03T20:36:48.323Z" }, - { url = "https://files.pythonhosted.org/packages/59/cf/c3ac8c80d8ced6c1f99b5d9674d397ce5d0e9d0939d788d67c010e19c65f/rapidfuzz-3.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0da54aa8547b3c2c188db3d1c7eb4d1bb6dd80baa8cdaeaec3d1da3346ec9caa", size = 1399854, upload-time = "2025-04-03T20:36:50.294Z" }, - { url = "https://files.pythonhosted.org/packages/09/5d/ca8698e452b349c8313faf07bfa84e7d1c2d2edf7ccc67bcfc49bee1259a/rapidfuzz-3.13.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df8e8c21e67afb9d7fbe18f42c6111fe155e801ab103c81109a61312927cc611", size = 5308962, upload-time = "2025-04-03T20:36:52.421Z" }, - { url = "https://files.pythonhosted.org/packages/66/0a/bebada332854e78e68f3d6c05226b23faca79d71362509dbcf7b002e33b7/rapidfuzz-3.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:461fd13250a2adf8e90ca9a0e1e166515cbcaa5e9c3b1f37545cbbeff9e77f6b", size = 1625016, upload-time = "2025-04-03T20:36:54.639Z" }, - { url = "https://files.pythonhosted.org/packages/de/0c/9e58d4887b86d7121d1c519f7050d1be5eb189d8a8075f5417df6492b4f5/rapidfuzz-3.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2b3dd5d206a12deca16870acc0d6e5036abeb70e3cad6549c294eff15591527", size = 1600414, upload-time = "2025-04-03T20:36:56.669Z" }, - { url = "https://files.pythonhosted.org/packages/9b/df/6096bc669c1311568840bdcbb5a893edc972d1c8d2b4b4325c21d54da5b1/rapidfuzz-3.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1343d745fbf4688e412d8f398c6e6d6f269db99a54456873f232ba2e7aeb4939", size = 3053179, upload-time = "2025-04-03T20:36:59.366Z" }, - { url = "https://files.pythonhosted.org/packages/f9/46/5179c583b75fce3e65a5cd79a3561bd19abd54518cb7c483a89b284bf2b9/rapidfuzz-3.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b1b065f370d54551dcc785c6f9eeb5bd517ae14c983d2784c064b3aa525896df", size = 2456856, upload-time = "2025-04-03T20:37:01.708Z" }, - { url = "https://files.pythonhosted.org/packages/6b/64/e9804212e3286d027ac35bbb66603c9456c2bce23f823b67d2f5cabc05c1/rapidfuzz-3.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:11b125d8edd67e767b2295eac6eb9afe0b1cdc82ea3d4b9257da4b8e06077798", size = 7567107, upload-time = "2025-04-03T20:37:04.521Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f2/7d69e7bf4daec62769b11757ffc31f69afb3ce248947aadbb109fefd9f65/rapidfuzz-3.13.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c33f9c841630b2bb7e69a3fb5c84a854075bb812c47620978bddc591f764da3d", size = 2854192, upload-time = "2025-04-03T20:37:06.905Z" }, - { url = "https://files.pythonhosted.org/packages/05/21/ab4ad7d7d0f653e6fe2e4ccf11d0245092bef94cdff587a21e534e57bda8/rapidfuzz-3.13.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ae4574cb66cf1e85d32bb7e9ec45af5409c5b3970b7ceb8dea90168024127566", size = 3398876, upload-time = "2025-04-03T20:37:09.692Z" }, - { url = "https://files.pythonhosted.org/packages/0f/a8/45bba94c2489cb1ee0130dcb46e1df4fa2c2b25269e21ffd15240a80322b/rapidfuzz-3.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e05752418b24bbd411841b256344c26f57da1148c5509e34ea39c7eb5099ab72", size = 4377077, upload-time = "2025-04-03T20:37:11.929Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f3/5e0c6ae452cbb74e5436d3445467447e8c32f3021f48f93f15934b8cffc2/rapidfuzz-3.13.0-cp313-cp313-win32.whl", hash = "sha256:0e1d08cb884805a543f2de1f6744069495ef527e279e05370dd7c83416af83f8", size = 1822066, upload-time = "2025-04-03T20:37:14.425Z" }, - { url = "https://files.pythonhosted.org/packages/96/e3/a98c25c4f74051df4dcf2f393176b8663bfd93c7afc6692c84e96de147a2/rapidfuzz-3.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264", size = 1615100, upload-time = "2025-04-03T20:37:16.611Z" }, - { url = "https://files.pythonhosted.org/packages/60/b1/05cd5e697c00cd46d7791915f571b38c8531f714832eff2c5e34537c49ee/rapidfuzz-3.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:3f32f15bacd1838c929b35c84b43618481e1b3d7a61b5ed2db0291b70ae88b53", size = 858976, upload-time = "2025-04-03T20:37:19.336Z" }, +version = "3.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/fc/a98b616db9a42dcdda7c78c76bdfdf6fe290ac4c5ffbb186f73ec981ad5b/rapidfuzz-3.14.1.tar.gz", hash = "sha256:b02850e7f7152bd1edff27e9d584505b84968cacedee7a734ec4050c655a803c", size = 57869570, upload-time = "2025-09-08T21:08:15.922Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/77/2f4887c9b786f203e50b816c1cde71f96642f194e6fa752acfa042cf53fd/rapidfuzz-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:809515194f628004aac1b1b280c3734c5ea0ccbd45938c9c9656a23ae8b8f553", size = 1932216, upload-time = "2025-09-08T21:06:09.342Z" }, + { url = "https://files.pythonhosted.org/packages/de/bd/b5e445d156cb1c2a87d36d8da53daf4d2a1d1729b4851660017898b49aa0/rapidfuzz-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0afcf2d6cb633d0d4260d8df6a40de2d9c93e9546e2c6b317ab03f89aa120ad7", size = 1393414, upload-time = "2025-09-08T21:06:10.959Z" }, + { url = "https://files.pythonhosted.org/packages/de/bd/98d065dd0a4479a635df855616980eaae1a1a07a876db9400d421b5b6371/rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1c3d07d53dcafee10599da8988d2b1f39df236aee501ecbd617bd883454fcd", size = 1377194, upload-time = "2025-09-08T21:06:12.471Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/1265547b771128b686f3c431377ff1db2fa073397ed082a25998a7b06d4e/rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e9ee3e1eb0a027717ee72fe34dc9ac5b3e58119f1bd8dd15bc19ed54ae3e62b", size = 1669573, upload-time = "2025-09-08T21:06:14.016Z" }, + { url = "https://files.pythonhosted.org/packages/a8/57/e73755c52fb451f2054196404ccc468577f8da023b3a48c80bce29ee5d4a/rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:70c845b64a033a20c44ed26bc890eeb851215148cc3e696499f5f65529afb6cb", size = 2217833, upload-time = "2025-09-08T21:06:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/20/14/7399c18c460e72d1b754e80dafc9f65cb42a46cc8f29cd57d11c0c4acc94/rapidfuzz-3.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26db0e815213d04234298dea0d884d92b9cb8d4ba954cab7cf67a35853128a33", size = 3159012, upload-time = "2025-09-08T21:06:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5e/24f0226ddb5440cabd88605d2491f99ae3748a6b27b0bc9703772892ced7/rapidfuzz-3.14.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:6ad3395a416f8b126ff11c788531f157c7debeb626f9d897c153ff8980da10fb", size = 1227032, upload-time = "2025-09-08T21:06:21.06Z" }, + { url = "https://files.pythonhosted.org/packages/40/43/1d54a4ad1a5fac2394d5f28a3108e2bf73c26f4f23663535e3139cfede9b/rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61c5b9ab6f730e6478aa2def566223712d121c6f69a94c7cc002044799442afd", size = 2395054, upload-time = "2025-09-08T21:06:23.482Z" }, + { url = "https://files.pythonhosted.org/packages/0c/71/e9864cd5b0f086c4a03791f5dfe0155a1b132f789fe19b0c76fbabd20513/rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13e0ea3d0c533969158727d1bb7a08c2cc9a816ab83f8f0dcfde7e38938ce3e6", size = 2524741, upload-time = "2025-09-08T21:06:26.825Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0c/53f88286b912faf4a3b2619a60df4f4a67bd0edcf5970d7b0c1143501f0c/rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6325ca435b99f4001aac919ab8922ac464999b100173317defb83eae34e82139", size = 2785311, upload-time = "2025-09-08T21:06:29.471Z" }, + { url = "https://files.pythonhosted.org/packages/53/9a/229c26dc4f91bad323f07304ee5ccbc28f0d21c76047a1e4f813187d0bad/rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:07a9fad3247e68798424bdc116c1094e88ecfabc17b29edf42a777520347648e", size = 3303630, upload-time = "2025-09-08T21:06:31.094Z" }, + { url = "https://files.pythonhosted.org/packages/05/de/20e330d6d58cbf83da914accd9e303048b7abae2f198886f65a344b69695/rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8ff5dbe78db0a10c1f916368e21d328935896240f71f721e073cf6c4c8cdedd", size = 4262364, upload-time = "2025-09-08T21:06:32.877Z" }, + { url = "https://files.pythonhosted.org/packages/1f/10/2327f83fad3534a8d69fe9cd718f645ec1fe828b60c0e0e97efc03bf12f8/rapidfuzz-3.14.1-cp312-cp312-win32.whl", hash = "sha256:9c83270e44a6ae7a39fc1d7e72a27486bccc1fa5f34e01572b1b90b019e6b566", size = 1711927, upload-time = "2025-09-08T21:06:34.669Z" }, + { url = "https://files.pythonhosted.org/packages/78/8d/199df0370133fe9f35bc72f3c037b53c93c5c1fc1e8d915cf7c1f6bb8557/rapidfuzz-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:e06664c7fdb51c708e082df08a6888fce4c5c416d7e3cc2fa66dd80eb76a149d", size = 1542045, upload-time = "2025-09-08T21:06:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/b3/c6/cc5d4bd1b16ea2657c80b745d8b1c788041a31fad52e7681496197b41562/rapidfuzz-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:6c7c26025f7934a169a23dafea6807cfc3fb556f1dd49229faf2171e5d8101cc", size = 813170, upload-time = "2025-09-08T21:06:38.001Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f2/0024cc8eead108c4c29337abe133d72ddf3406ce9bbfbcfc110414a7ea07/rapidfuzz-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8d69f470d63ee824132ecd80b1974e1d15dd9df5193916901d7860cef081a260", size = 1926515, upload-time = "2025-09-08T21:06:39.834Z" }, + { url = "https://files.pythonhosted.org/packages/12/ae/6cb211f8930bea20fa989b23f31ee7f92940caaf24e3e510d242a1b28de4/rapidfuzz-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6f571d20152fc4833b7b5e781b36d5e4f31f3b5a596a3d53cf66a1bd4436b4f4", size = 1388431, upload-time = "2025-09-08T21:06:41.73Z" }, + { url = "https://files.pythonhosted.org/packages/39/88/bfec24da0607c39e5841ced5594ea1b907d20f83adf0e3ee87fa454a425b/rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61d77e09b2b6bc38228f53b9ea7972a00722a14a6048be9a3672fb5cb08bad3a", size = 1375664, upload-time = "2025-09-08T21:06:43.737Z" }, + { url = "https://files.pythonhosted.org/packages/f4/43/9f282ba539e404bdd7052c7371d3aaaa1a9417979d2a1d8332670c7f385a/rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b41d95ef86a6295d353dc3bb6c80550665ba2c3bef3a9feab46074d12a9af8f", size = 1668113, upload-time = "2025-09-08T21:06:45.758Z" }, + { url = "https://files.pythonhosted.org/packages/7f/2f/0b3153053b1acca90969eb0867922ac8515b1a8a48706a3215c2db60e87c/rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0591df2e856ad583644b40a2b99fb522f93543c65e64b771241dda6d1cfdc96b", size = 2212875, upload-time = "2025-09-08T21:06:47.447Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/623001dddc518afaa08ed1fbbfc4005c8692b7a32b0f08b20c506f17a770/rapidfuzz-3.14.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f277801f55b2f3923ef2de51ab94689a0671a4524bf7b611de979f308a54cd6f", size = 3161181, upload-time = "2025-09-08T21:06:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b7/d8404ed5ad56eb74463e5ebf0a14f0019d7eb0e65e0323f709fe72e0884c/rapidfuzz-3.14.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:893fdfd4f66ebb67f33da89eb1bd1674b7b30442fdee84db87f6cb9074bf0ce9", size = 1225495, upload-time = "2025-09-08T21:06:51.056Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6c/b96af62bc7615d821e3f6b47563c265fd7379d7236dfbc1cbbcce8beb1d2/rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fe2651258c1f1afa9b66f44bf82f639d5f83034f9804877a1bbbae2120539ad1", size = 2396294, upload-time = "2025-09-08T21:06:53.063Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b7/c60c9d22a7debed8b8b751f506a4cece5c22c0b05e47a819d6b47bc8c14e/rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ace21f7a78519d8e889b1240489cd021c5355c496cb151b479b741a4c27f0a25", size = 2529629, upload-time = "2025-09-08T21:06:55.188Z" }, + { url = "https://files.pythonhosted.org/packages/25/94/a9ec7ccb28381f14de696ffd51c321974762f137679df986f5375d35264f/rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cb5acf24590bc5e57027283b015950d713f9e4d155fda5cfa71adef3b3a84502", size = 2782960, upload-time = "2025-09-08T21:06:57.339Z" }, + { url = "https://files.pythonhosted.org/packages/68/80/04e5276d223060eca45250dbf79ea39940c0be8b3083661d58d57572c2c5/rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:67ea46fa8cc78174bad09d66b9a4b98d3068e85de677e3c71ed931a1de28171f", size = 3298427, upload-time = "2025-09-08T21:06:59.319Z" }, + { url = "https://files.pythonhosted.org/packages/4a/63/24759b2a751562630b244e68ccaaf7a7525c720588fcc77c964146355aee/rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:44e741d785de57d1a7bae03599c1cbc7335d0b060a35e60c44c382566e22782e", size = 4267736, upload-time = "2025-09-08T21:07:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/18/a4/73f1b1f7f44d55f40ffbffe85e529eb9d7e7f7b2ffc0931760eadd163995/rapidfuzz-3.14.1-cp313-cp313-win32.whl", hash = "sha256:b1fe6001baa9fa36bcb565e24e88830718f6c90896b91ceffcb48881e3adddbc", size = 1710515, upload-time = "2025-09-08T21:07:03.16Z" }, + { url = "https://files.pythonhosted.org/packages/6a/8b/a8fe5a6ee4d06fd413aaa9a7e0a23a8630c4b18501509d053646d18c2aa7/rapidfuzz-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:83b8cc6336709fa5db0579189bfd125df280a554af544b2dc1c7da9cdad7e44d", size = 1540081, upload-time = "2025-09-08T21:07:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/ac/fe/4b0ac16c118a2367d85450b45251ee5362661e9118a1cef88aae1765ffff/rapidfuzz-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:cf75769662eadf5f9bd24e865c19e5ca7718e879273dce4e7b3b5824c4da0eb4", size = 812725, upload-time = "2025-09-08T21:07:07.148Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cb/1ad9a76d974d153783f8e0be8dbe60ec46488fac6e519db804e299e0da06/rapidfuzz-3.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d937dbeda71c921ef6537c6d41a84f1b8112f107589c9977059de57a1d726dd6", size = 1945173, upload-time = "2025-09-08T21:07:08.893Z" }, + { url = "https://files.pythonhosted.org/packages/d9/61/959ed7460941d8a81cbf6552b9c45564778a36cf5e5aa872558b30fc02b2/rapidfuzz-3.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a2d80cc1a4fcc7e259ed4f505e70b36433a63fa251f1bb69ff279fe376c5efd", size = 1413949, upload-time = "2025-09-08T21:07:11.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a0/f46fca44457ca1f25f23cc1f06867454fc3c3be118cd10b552b0ab3e58a2/rapidfuzz-3.14.1-cp313-cp313t-win32.whl", hash = "sha256:40875e0c06f1a388f1cab3885744f847b557e0b1642dfc31ff02039f9f0823ef", size = 1760666, upload-time = "2025-09-08T21:07:12.884Z" }, + { url = "https://files.pythonhosted.org/packages/9b/d0/7a5d9c04446f8b66882b0fae45b36a838cf4d31439b5d1ab48a9d17c8e57/rapidfuzz-3.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:876dc0c15552f3d704d7fb8d61bdffc872ff63bedf683568d6faad32e51bbce8", size = 1579760, upload-time = "2025-09-08T21:07:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/4e/aa/2c03ae112320d0746f2c869cae68c413f3fe3b6403358556f2b747559723/rapidfuzz-3.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:61458e83b0b3e2abc3391d0953c47d6325e506ba44d6a25c869c4401b3bc222c", size = 832088, upload-time = "2025-09-08T21:07:17.03Z" }, + { url = "https://files.pythonhosted.org/packages/d6/36/53debca45fbe693bd6181fb05b6a2fd561c87669edb82ec0d7c1961a43f0/rapidfuzz-3.14.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e84d9a844dc2e4d5c4cabd14c096374ead006583304333c14a6fbde51f612a44", size = 1926336, upload-time = "2025-09-08T21:07:18.809Z" }, + { url = "https://files.pythonhosted.org/packages/ae/32/b874f48609665fcfeaf16cbaeb2bbc210deef2b88e996c51cfc36c3eb7c3/rapidfuzz-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:40301b93b99350edcd02dbb22e37ca5f2a75d0db822e9b3c522da451a93d6f27", size = 1389653, upload-time = "2025-09-08T21:07:20.667Z" }, + { url = "https://files.pythonhosted.org/packages/97/25/f6c5a1ff4ec11edadacb270e70b8415f51fa2f0d5730c2c552b81651fbe3/rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fedd5097a44808dddf341466866e5c57a18a19a336565b4ff50aa8f09eb528f6", size = 1380911, upload-time = "2025-09-08T21:07:22.584Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f3/d322202ef8fab463759b51ebfaa33228100510c82e6153bd7a922e150270/rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e3e61c9e80d8c26709d8aa5c51fdd25139c81a4ab463895f8a567f8347b0548", size = 1673515, upload-time = "2025-09-08T21:07:24.417Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b9/6b2a97f4c6be96cac3749f32301b8cdf751ce5617b1c8934c96586a0662b/rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da011a373722fac6e64687297a1d17dc8461b82cb12c437845d5a5b161bc24b9", size = 2219394, upload-time = "2025-09-08T21:07:26.402Z" }, + { url = "https://files.pythonhosted.org/packages/11/bf/afb76adffe4406e6250f14ce48e60a7eb05d4624945bd3c044cfda575fbc/rapidfuzz-3.14.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5967d571243cfb9ad3710e6e628ab68c421a237b76e24a67ac22ee0ff12784d6", size = 3163582, upload-time = "2025-09-08T21:07:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/42/34/e6405227560f61e956cb4c5de653b0f874751c5ada658d3532d6c1df328e/rapidfuzz-3.14.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:474f416cbb9099676de54aa41944c154ba8d25033ee460f87bb23e54af6d01c9", size = 1221116, upload-time = "2025-09-08T21:07:30.8Z" }, + { url = "https://files.pythonhosted.org/packages/55/e6/5b757e2e18de384b11d1daf59608453f0baf5d5d8d1c43e1a964af4dc19a/rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ae2d57464b59297f727c4e201ea99ec7b13935f1f056c753e8103da3f2fc2404", size = 2402670, upload-time = "2025-09-08T21:07:32.702Z" }, + { url = "https://files.pythonhosted.org/packages/43/c4/d753a415fe54531aa882e288db5ed77daaa72e05c1a39e1cbac00d23024f/rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:57047493a1f62f11354c7143c380b02f1b355c52733e6b03adb1cb0fe8fb8816", size = 2521659, upload-time = "2025-09-08T21:07:35.218Z" }, + { url = "https://files.pythonhosted.org/packages/cd/28/d4e7fe1515430db98f42deb794c7586a026d302fe70f0216b638d89cf10f/rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4acc20776f225ee37d69517a237c090b9fa7e0836a0b8bc58868e9168ba6ef6f", size = 2788552, upload-time = "2025-09-08T21:07:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/4f/00/eab05473af7a2cafb4f3994bc6bf408126b8eec99a569aac6254ac757db4/rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4373f914ff524ee0146919dea96a40a8200ab157e5a15e777a74a769f73d8a4a", size = 3306261, upload-time = "2025-09-08T21:07:39.624Z" }, + { url = "https://files.pythonhosted.org/packages/d1/31/2feb8dfcfcff6508230cd2ccfdde7a8bf988c6fda142fe9ce5d3eb15704d/rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:37017b84953927807847016620d61251fe236bd4bcb25e27b6133d955bb9cafb", size = 4269522, upload-time = "2025-09-08T21:07:41.663Z" }, + { url = "https://files.pythonhosted.org/packages/a3/99/250538d73c8fbab60597c3d131a11ef2a634d38b44296ca11922794491ac/rapidfuzz-3.14.1-cp314-cp314-win32.whl", hash = "sha256:c8d1dd1146539e093b84d0805e8951475644af794ace81d957ca612e3eb31598", size = 1745018, upload-time = "2025-09-08T21:07:44.313Z" }, + { url = "https://files.pythonhosted.org/packages/c5/15/d50839d20ad0743aded25b08a98ffb872f4bfda4e310bac6c111fcf6ea1f/rapidfuzz-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:f51c7571295ea97387bac4f048d73cecce51222be78ed808263b45c79c40a440", size = 1587666, upload-time = "2025-09-08T21:07:46.917Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ff/d73fec989213fb6f0b6f15ee4bbdf2d88b0686197951a06b036111cd1c7d/rapidfuzz-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:01eab10ec90912d7d28b3f08f6c91adbaf93458a53f849ff70776ecd70dd7a7a", size = 835780, upload-time = "2025-09-08T21:07:49.256Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e7/f0a242687143cebd33a1fb165226b73bd9496d47c5acfad93de820a18fa8/rapidfuzz-3.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:60879fcae2f7618403c4c746a9a3eec89327d73148fb6e89a933b78442ff0669", size = 1945182, upload-time = "2025-09-08T21:07:51.84Z" }, + { url = "https://files.pythonhosted.org/packages/96/29/ca8a3f8525e3d0e7ab49cb927b5fb4a54855f794c9ecd0a0b60a6c96a05f/rapidfuzz-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f94d61e44db3fc95a74006a394257af90fa6e826c900a501d749979ff495d702", size = 1413946, upload-time = "2025-09-08T21:07:53.702Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ef/6fd10aa028db19c05b4ac7fe77f5613e4719377f630c709d89d7a538eea2/rapidfuzz-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:93b6294a3ffab32a9b5f9b5ca048fa0474998e7e8bb0f2d2b5e819c64cb71ec7", size = 1795851, upload-time = "2025-09-08T21:07:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/e4/30/acd29ebd906a50f9e0f27d5f82a48cf5e8854637b21489bd81a2459985cf/rapidfuzz-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6cb56b695421538fdbe2c0c85888b991d833b8637d2f2b41faa79cea7234c000", size = 1626748, upload-time = "2025-09-08T21:07:58.166Z" }, + { url = "https://files.pythonhosted.org/packages/c1/f4/dfc7b8c46b1044a47f7ca55deceb5965985cff3193906cb32913121e6652/rapidfuzz-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7cd312c380d3ce9d35c3ec9726b75eee9da50e8a38e89e229a03db2262d3d96b", size = 853771, upload-time = "2025-09-08T21:08:00.816Z" }, ] [[package]] @@ -1231,16 +1316,16 @@ wheels = [ [[package]] name = "rich-toolkit" -version = "0.15.0" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/65/36/cdb3d51371ad0cccbf1541506304783bd72d55790709b8eb68c0d401a13a/rich_toolkit-0.15.0.tar.gz", hash = "sha256:3f5730e9f2d36d0bfe01cf723948b7ecf4cc355d2b71e2c00e094f7963128c09", size = 115118, upload-time = "2025-08-11T10:55:37.909Z" } +sdist = { url = "https://files.pythonhosted.org/packages/67/33/1a18839aaa8feef7983590c05c22c9c09d245ada6017d118325bbfcc7651/rich_toolkit-0.15.1.tar.gz", hash = "sha256:6f9630eb29f3843d19d48c3bd5706a086d36d62016687f9d0efa027ddc2dd08a", size = 115322, upload-time = "2025-09-04T09:28:11.789Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/e4/b0794eefb3cf78566b15e5bf576492c1d4a92ce5f6da55675bc11e9ef5d8/rich_toolkit-0.15.0-py3-none-any.whl", hash = "sha256:ddb91008283d4a7989fd8ff0324a48773a7a2276229c6a3070755645538ef1bb", size = 29062, upload-time = "2025-08-11T10:55:37.152Z" }, + { url = "https://files.pythonhosted.org/packages/c8/49/42821d55ead7b5a87c8d121edf323cb393d8579f63e933002ade900b784f/rich_toolkit-0.15.1-py3-none-any.whl", hash = "sha256:36a0b1d9a135d26776e4b78f1d5c2655da6e0ef432380b5c6b523c8d8ab97478", size = 29412, upload-time = "2025-09-04T09:28:10.587Z" }, ] [[package]] @@ -1291,83 +1376,83 @@ wheels = [ [[package]] name = "rpds-py" -version = "0.27.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/d9/991a0dee12d9fc53ed027e26a26a64b151d77252ac477e22666b9688bc16/rpds_py-0.27.0.tar.gz", hash = "sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f", size = 27420, upload-time = "2025-08-07T08:26:39.624Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/17/e67309ca1ac993fa1888a0d9b2f5ccc1f67196ace32e76c9f8e1dbbbd50c/rpds_py-0.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4", size = 362611, upload-time = "2025-08-07T08:23:44.773Z" }, - { url = "https://files.pythonhosted.org/packages/93/2e/28c2fb84aa7aa5d75933d1862d0f7de6198ea22dfd9a0cca06e8a4e7509e/rpds_py-0.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b", size = 347680, upload-time = "2025-08-07T08:23:46.014Z" }, - { url = "https://files.pythonhosted.org/packages/44/3e/9834b4c8f4f5fe936b479e623832468aa4bd6beb8d014fecaee9eac6cdb1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e", size = 384600, upload-time = "2025-08-07T08:23:48Z" }, - { url = "https://files.pythonhosted.org/packages/19/78/744123c7b38865a965cd9e6f691fde7ef989a00a256fa8bf15b75240d12f/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34", size = 400697, upload-time = "2025-08-07T08:23:49.407Z" }, - { url = "https://files.pythonhosted.org/packages/32/97/3c3d32fe7daee0a1f1a678b6d4dfb8c4dcf88197fa2441f9da7cb54a8466/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8", size = 517781, upload-time = "2025-08-07T08:23:50.557Z" }, - { url = "https://files.pythonhosted.org/packages/b2/be/28f0e3e733680aa13ecec1212fc0f585928a206292f14f89c0b8a684cad1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726", size = 406449, upload-time = "2025-08-07T08:23:51.732Z" }, - { url = "https://files.pythonhosted.org/packages/95/ae/5d15c83e337c082d0367053baeb40bfba683f42459f6ebff63a2fd7e5518/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e", size = 386150, upload-time = "2025-08-07T08:23:52.822Z" }, - { url = "https://files.pythonhosted.org/packages/bf/65/944e95f95d5931112829e040912b25a77b2e7ed913ea5fe5746aa5c1ce75/rpds_py-0.27.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3", size = 406100, upload-time = "2025-08-07T08:23:54.339Z" }, - { url = "https://files.pythonhosted.org/packages/21/a4/1664b83fae02894533cd11dc0b9f91d673797c2185b7be0f7496107ed6c5/rpds_py-0.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e", size = 421345, upload-time = "2025-08-07T08:23:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/7c/26/b7303941c2b0823bfb34c71378249f8beedce57301f400acb04bb345d025/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f", size = 561891, upload-time = "2025-08-07T08:23:56.951Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c8/48623d64d4a5a028fa99576c768a6159db49ab907230edddc0b8468b998b/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03", size = 591756, upload-time = "2025-08-07T08:23:58.146Z" }, - { url = "https://files.pythonhosted.org/packages/b3/51/18f62617e8e61cc66334c9fb44b1ad7baae3438662098efbc55fb3fda453/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374", size = 557088, upload-time = "2025-08-07T08:23:59.6Z" }, - { url = "https://files.pythonhosted.org/packages/bd/4c/e84c3a276e2496a93d245516be6b49e20499aa8ca1c94d59fada0d79addc/rpds_py-0.27.0-cp312-cp312-win32.whl", hash = "sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97", size = 221926, upload-time = "2025-08-07T08:24:00.695Z" }, - { url = "https://files.pythonhosted.org/packages/83/89/9d0fbcef64340db0605eb0a0044f258076f3ae0a3b108983b2c614d96212/rpds_py-0.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5", size = 233235, upload-time = "2025-08-07T08:24:01.846Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b0/e177aa9f39cbab060f96de4a09df77d494f0279604dc2f509263e21b05f9/rpds_py-0.27.0-cp312-cp312-win_arm64.whl", hash = "sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9", size = 223315, upload-time = "2025-08-07T08:24:03.337Z" }, - { url = "https://files.pythonhosted.org/packages/81/d2/dfdfd42565a923b9e5a29f93501664f5b984a802967d48d49200ad71be36/rpds_py-0.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff", size = 362133, upload-time = "2025-08-07T08:24:04.508Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4a/0a2e2460c4b66021d349ce9f6331df1d6c75d7eea90df9785d333a49df04/rpds_py-0.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367", size = 347128, upload-time = "2025-08-07T08:24:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/35/8d/7d1e4390dfe09d4213b3175a3f5a817514355cb3524593380733204f20b9/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185", size = 384027, upload-time = "2025-08-07T08:24:06.841Z" }, - { url = "https://files.pythonhosted.org/packages/c1/65/78499d1a62172891c8cd45de737b2a4b84a414b6ad8315ab3ac4945a5b61/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc", size = 399973, upload-time = "2025-08-07T08:24:08.143Z" }, - { url = "https://files.pythonhosted.org/packages/10/a1/1c67c1d8cc889107b19570bb01f75cf49852068e95e6aee80d22915406fc/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe", size = 515295, upload-time = "2025-08-07T08:24:09.711Z" }, - { url = "https://files.pythonhosted.org/packages/df/27/700ec88e748436b6c7c4a2262d66e80f8c21ab585d5e98c45e02f13f21c0/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9", size = 406737, upload-time = "2025-08-07T08:24:11.182Z" }, - { url = "https://files.pythonhosted.org/packages/33/cc/6b0ee8f0ba3f2df2daac1beda17fde5cf10897a7d466f252bd184ef20162/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c", size = 385898, upload-time = "2025-08-07T08:24:12.798Z" }, - { url = "https://files.pythonhosted.org/packages/e8/7e/c927b37d7d33c0a0ebf249cc268dc2fcec52864c1b6309ecb960497f2285/rpds_py-0.27.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295", size = 405785, upload-time = "2025-08-07T08:24:14.906Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/8ed50746d909dcf402af3fa58b83d5a590ed43e07251d6b08fad1a535ba6/rpds_py-0.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43", size = 419760, upload-time = "2025-08-07T08:24:16.129Z" }, - { url = "https://files.pythonhosted.org/packages/d3/60/2b2071aee781cb3bd49f94d5d35686990b925e9b9f3e3d149235a6f5d5c1/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432", size = 561201, upload-time = "2025-08-07T08:24:17.645Z" }, - { url = "https://files.pythonhosted.org/packages/98/1f/27b67304272521aaea02be293fecedce13fa351a4e41cdb9290576fc6d81/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b", size = 591021, upload-time = "2025-08-07T08:24:18.999Z" }, - { url = "https://files.pythonhosted.org/packages/db/9b/a2fadf823164dd085b1f894be6443b0762a54a7af6f36e98e8fcda69ee50/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d", size = 556368, upload-time = "2025-08-07T08:24:20.54Z" }, - { url = "https://files.pythonhosted.org/packages/24/f3/6d135d46a129cda2e3e6d4c5e91e2cc26ea0428c6cf152763f3f10b6dd05/rpds_py-0.27.0-cp313-cp313-win32.whl", hash = "sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd", size = 221236, upload-time = "2025-08-07T08:24:22.144Z" }, - { url = "https://files.pythonhosted.org/packages/c5/44/65d7494f5448ecc755b545d78b188440f81da98b50ea0447ab5ebfdf9bd6/rpds_py-0.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2", size = 232634, upload-time = "2025-08-07T08:24:23.642Z" }, - { url = "https://files.pythonhosted.org/packages/70/d9/23852410fadab2abb611733933401de42a1964ce6600a3badae35fbd573e/rpds_py-0.27.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac", size = 222783, upload-time = "2025-08-07T08:24:25.098Z" }, - { url = "https://files.pythonhosted.org/packages/15/75/03447917f78512b34463f4ef11066516067099a0c466545655503bed0c77/rpds_py-0.27.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774", size = 359154, upload-time = "2025-08-07T08:24:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/6b/fc/4dac4fa756451f2122ddaf136e2c6aeb758dc6fdbe9ccc4bc95c98451d50/rpds_py-0.27.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b", size = 343909, upload-time = "2025-08-07T08:24:27.405Z" }, - { url = "https://files.pythonhosted.org/packages/7b/81/723c1ed8e6f57ed9d8c0c07578747a2d3d554aaefc1ab89f4e42cfeefa07/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd", size = 379340, upload-time = "2025-08-07T08:24:28.714Z" }, - { url = "https://files.pythonhosted.org/packages/98/16/7e3740413de71818ce1997df82ba5f94bae9fff90c0a578c0e24658e6201/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb", size = 391655, upload-time = "2025-08-07T08:24:30.223Z" }, - { url = "https://files.pythonhosted.org/packages/e0/63/2a9f510e124d80660f60ecce07953f3f2d5f0b96192c1365443859b9c87f/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433", size = 513017, upload-time = "2025-08-07T08:24:31.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4e/cf6ff311d09776c53ea1b4f2e6700b9d43bb4e99551006817ade4bbd6f78/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615", size = 402058, upload-time = "2025-08-07T08:24:32.613Z" }, - { url = "https://files.pythonhosted.org/packages/88/11/5e36096d474cb10f2a2d68b22af60a3bc4164fd8db15078769a568d9d3ac/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8", size = 383474, upload-time = "2025-08-07T08:24:33.767Z" }, - { url = "https://files.pythonhosted.org/packages/db/a2/3dff02805b06058760b5eaa6d8cb8db3eb3e46c9e452453ad5fc5b5ad9fe/rpds_py-0.27.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858", size = 400067, upload-time = "2025-08-07T08:24:35.021Z" }, - { url = "https://files.pythonhosted.org/packages/67/87/eed7369b0b265518e21ea836456a4ed4a6744c8c12422ce05bce760bb3cf/rpds_py-0.27.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5", size = 412085, upload-time = "2025-08-07T08:24:36.267Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/f50b2ab2fbb422fbb389fe296e70b7a6b5ea31b263ada5c61377e710a924/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9", size = 555928, upload-time = "2025-08-07T08:24:37.573Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/b18eb51045d06887666c3560cd4bbb6819127b43d758f5adb82b5f56f7d1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79", size = 585527, upload-time = "2025-08-07T08:24:39.391Z" }, - { url = "https://files.pythonhosted.org/packages/be/03/a3dd6470fc76499959b00ae56295b76b4bdf7c6ffc60d62006b1217567e1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c", size = 554211, upload-time = "2025-08-07T08:24:40.6Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d1/ee5fd1be395a07423ac4ca0bcc05280bf95db2b155d03adefeb47d5ebf7e/rpds_py-0.27.0-cp313-cp313t-win32.whl", hash = "sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23", size = 216624, upload-time = "2025-08-07T08:24:42.204Z" }, - { url = "https://files.pythonhosted.org/packages/1c/94/4814c4c858833bf46706f87349c37ca45e154da7dbbec9ff09f1abeb08cc/rpds_py-0.27.0-cp313-cp313t-win_amd64.whl", hash = "sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1", size = 230007, upload-time = "2025-08-07T08:24:43.329Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a5/8fffe1c7dc7c055aa02df310f9fb71cfc693a4d5ccc5de2d3456ea5fb022/rpds_py-0.27.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb", size = 362595, upload-time = "2025-08-07T08:24:44.478Z" }, - { url = "https://files.pythonhosted.org/packages/bc/c7/4e4253fd2d4bb0edbc0b0b10d9f280612ca4f0f990e3c04c599000fe7d71/rpds_py-0.27.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f", size = 347252, upload-time = "2025-08-07T08:24:45.678Z" }, - { url = "https://files.pythonhosted.org/packages/f3/c8/3d1a954d30f0174dd6baf18b57c215da03cf7846a9d6e0143304e784cddc/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64", size = 384886, upload-time = "2025-08-07T08:24:46.86Z" }, - { url = "https://files.pythonhosted.org/packages/e0/52/3c5835f2df389832b28f9276dd5395b5a965cea34226e7c88c8fbec2093c/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015", size = 399716, upload-time = "2025-08-07T08:24:48.174Z" }, - { url = "https://files.pythonhosted.org/packages/40/73/176e46992461a1749686a2a441e24df51ff86b99c2d34bf39f2a5273b987/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0", size = 517030, upload-time = "2025-08-07T08:24:49.52Z" }, - { url = "https://files.pythonhosted.org/packages/79/2a/7266c75840e8c6e70effeb0d38922a45720904f2cd695e68a0150e5407e2/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89", size = 408448, upload-time = "2025-08-07T08:24:50.727Z" }, - { url = "https://files.pythonhosted.org/packages/e6/5f/a7efc572b8e235093dc6cf39f4dbc8a7f08e65fdbcec7ff4daeb3585eef1/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d", size = 387320, upload-time = "2025-08-07T08:24:52.004Z" }, - { url = "https://files.pythonhosted.org/packages/a2/eb/9ff6bc92efe57cf5a2cb74dee20453ba444b6fdc85275d8c99e0d27239d1/rpds_py-0.27.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51", size = 407414, upload-time = "2025-08-07T08:24:53.664Z" }, - { url = "https://files.pythonhosted.org/packages/fb/bd/3b9b19b00d5c6e1bd0f418c229ab0f8d3b110ddf7ec5d9d689ef783d0268/rpds_py-0.27.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c", size = 420766, upload-time = "2025-08-07T08:24:55.917Z" }, - { url = "https://files.pythonhosted.org/packages/17/6b/521a7b1079ce16258c70805166e3ac6ec4ee2139d023fe07954dc9b2d568/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4", size = 562409, upload-time = "2025-08-07T08:24:57.17Z" }, - { url = "https://files.pythonhosted.org/packages/8b/bf/65db5bfb14ccc55e39de8419a659d05a2a9cd232f0a699a516bb0991da7b/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e", size = 590793, upload-time = "2025-08-07T08:24:58.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/b8/82d368b378325191ba7aae8f40f009b78057b598d4394d1f2cdabaf67b3f/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e", size = 558178, upload-time = "2025-08-07T08:24:59.756Z" }, - { url = "https://files.pythonhosted.org/packages/f6/ff/f270bddbfbc3812500f8131b1ebbd97afd014cd554b604a3f73f03133a36/rpds_py-0.27.0-cp314-cp314-win32.whl", hash = "sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6", size = 222355, upload-time = "2025-08-07T08:25:01.027Z" }, - { url = "https://files.pythonhosted.org/packages/bf/20/fdab055b1460c02ed356a0e0b0a78c1dd32dc64e82a544f7b31c9ac643dc/rpds_py-0.27.0-cp314-cp314-win_amd64.whl", hash = "sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a", size = 234007, upload-time = "2025-08-07T08:25:02.268Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a8/694c060005421797a3be4943dab8347c76c2b429a9bef68fb2c87c9e70c7/rpds_py-0.27.0-cp314-cp314-win_arm64.whl", hash = "sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d", size = 223527, upload-time = "2025-08-07T08:25:03.45Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f9/77f4c90f79d2c5ca8ce6ec6a76cb4734ee247de6b3a4f337e289e1f00372/rpds_py-0.27.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828", size = 359469, upload-time = "2025-08-07T08:25:04.648Z" }, - { url = "https://files.pythonhosted.org/packages/c0/22/b97878d2f1284286fef4172069e84b0b42b546ea7d053e5fb7adb9ac6494/rpds_py-0.27.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669", size = 343960, upload-time = "2025-08-07T08:25:05.863Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b0/dfd55b5bb480eda0578ae94ef256d3061d20b19a0f5e18c482f03e65464f/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd", size = 380201, upload-time = "2025-08-07T08:25:07.513Z" }, - { url = "https://files.pythonhosted.org/packages/28/22/e1fa64e50d58ad2b2053077e3ec81a979147c43428de9e6de68ddf6aff4e/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec", size = 392111, upload-time = "2025-08-07T08:25:09.149Z" }, - { url = "https://files.pythonhosted.org/packages/49/f9/43ab7a43e97aedf6cea6af70fdcbe18abbbc41d4ae6cdec1bfc23bbad403/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303", size = 515863, upload-time = "2025-08-07T08:25:10.431Z" }, - { url = "https://files.pythonhosted.org/packages/38/9b/9bd59dcc636cd04d86a2d20ad967770bf348f5eb5922a8f29b547c074243/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b", size = 402398, upload-time = "2025-08-07T08:25:11.819Z" }, - { url = "https://files.pythonhosted.org/packages/71/bf/f099328c6c85667aba6b66fa5c35a8882db06dcd462ea214be72813a0dd2/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410", size = 384665, upload-time = "2025-08-07T08:25:13.194Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c5/9c1f03121ece6634818490bd3c8be2c82a70928a19de03467fb25a3ae2a8/rpds_py-0.27.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156", size = 400405, upload-time = "2025-08-07T08:25:14.417Z" }, - { url = "https://files.pythonhosted.org/packages/b5/b8/e25d54af3e63ac94f0c16d8fe143779fe71ff209445a0c00d0f6984b6b2c/rpds_py-0.27.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2", size = 413179, upload-time = "2025-08-07T08:25:15.664Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d1/406b3316433fe49c3021546293a04bc33f1478e3ec7950215a7fce1a1208/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1", size = 556895, upload-time = "2025-08-07T08:25:17.061Z" }, - { url = "https://files.pythonhosted.org/packages/5f/bc/3697c0c21fcb9a54d46ae3b735eb2365eea0c2be076b8f770f98e07998de/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42", size = 585464, upload-time = "2025-08-07T08:25:18.406Z" }, - { url = "https://files.pythonhosted.org/packages/63/09/ee1bb5536f99f42c839b177d552f6114aa3142d82f49cef49261ed28dbe0/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae", size = 555090, upload-time = "2025-08-07T08:25:20.461Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2c/363eada9e89f7059199d3724135a86c47082cbf72790d6ba2f336d146ddb/rpds_py-0.27.0-cp314-cp314t-win32.whl", hash = "sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5", size = 218001, upload-time = "2025-08-07T08:25:21.761Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3f/d6c216ed5199c9ef79e2a33955601f454ed1e7420a93b89670133bca5ace/rpds_py-0.27.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391", size = 230993, upload-time = "2025-08-07T08:25:23.34Z" }, +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" }, + { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" }, + { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" }, + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, ] [[package]] @@ -1465,15 +1550,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.35.0" +version = "2.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/83/055dc157b719651ef13db569bb8cf2103df11174478649735c1b2bf3f6bc/sentry_sdk-2.35.0.tar.gz", hash = "sha256:5ea58d352779ce45d17bc2fa71ec7185205295b83a9dbb5707273deb64720092", size = 343014, upload-time = "2025-08-14T17:11:20.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/22/60fd703b34d94d216b2387e048ac82de3e86b63bc28869fb076f8bb0204a/sentry_sdk-2.38.0.tar.gz", hash = "sha256:792d2af45e167e2f8a3347143f525b9b6bac6f058fb2014720b40b84ccbeb985", size = 348116, upload-time = "2025-09-15T15:00:37.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3d/742617a7c644deb0c1628dcf6bb2d2165ab7c6aab56fe5222758994007f8/sentry_sdk-2.35.0-py2.py3-none-any.whl", hash = "sha256:6e0c29b9a5d34de8575ffb04d289a987ff3053cf2c98ede445bea995e3830263", size = 363806, upload-time = "2025-08-14T17:11:18.29Z" }, + { url = "https://files.pythonhosted.org/packages/7a/84/bde4c4bbb269b71bc09316af8eb00da91f67814d40337cc12ef9c8742541/sentry_sdk-2.38.0-py2.py3-none-any.whl", hash = "sha256:2324aea8573a3fa1576df7fb4d65c4eb8d9929c8fa5939647397a07179eef8d0", size = 370346, upload-time = "2025-09-15T15:00:35.821Z" }, ] [[package]] @@ -1514,84 +1599,24 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.7" +version = "2.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, -] - -[[package]] -name = "certcc-ssvc" -source = { editable = "." } -dependencies = [ - { name = "fastapi", extra = ["all", "standard"] }, - { name = "jsonschema" }, - { name = "markdown-exec", extra = ["ansi"] }, - { name = "mkdocs" }, - { name = "mkdocs-bibtex" }, - { name = "mkdocs-include-markdown-plugin" }, - { name = "mkdocs-material" }, - { name = "mkdocs-material-extensions" }, - { name = "mkdocs-print-site-plugin" }, - { name = "mkdocs-table-reader-plugin" }, - { name = "mkdocstrings" }, - { name = "mkdocstrings-python" }, - { name = "networkx" }, - { name = "pandas" }, - { name = "pydantic" }, - { name = "scikit-learn" }, - { name = "scipy" }, - { name = "semver" }, - { name = "thefuzz" }, -] - -[package.dev-dependencies] -dev = [ - { name = "linkchecker" }, - { name = "pytest" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", extras = ["all", "standard"], specifier = ">=0.116.1" }, - { name = "jsonschema", specifier = "==4.25.1" }, - { name = "markdown-exec", extras = ["ansi"], specifier = "==1.11.0" }, - { name = "mkdocs", specifier = "==1.6.1" }, - { name = "mkdocs-bibtex", specifier = "==4.4.0" }, - { name = "mkdocs-include-markdown-plugin", specifier = "==7.1.6" }, - { name = "mkdocs-material", specifier = "==9.6.18" }, - { name = "mkdocs-material-extensions", specifier = "==1.3.1" }, - { name = "mkdocs-print-site-plugin", specifier = "==2.8" }, - { name = "mkdocs-table-reader-plugin", specifier = "==3.1.0" }, - { name = "mkdocstrings", specifier = "==0.30.0" }, - { name = "mkdocstrings-python", specifier = "==1.17.0" }, - { name = "networkx", specifier = "==3.4.2" }, - { name = "pandas", specifier = "==2.3.2" }, - { name = "pydantic", specifier = "==2.11.7" }, - { name = "scikit-learn", specifier = "==1.6.1" }, - { name = "scipy", specifier = "==1.16.1" }, - { name = "semver", specifier = "==3.0.4" }, - { name = "thefuzz", specifier = "==0.22.1" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "linkchecker", specifier = ">=10.6.0" }, - { name = "pytest", specifier = ">=8.4.1" }, + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, ] [[package]] name = "starlette" -version = "0.47.2" +version = "0.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/57/d062573f391d062710d4088fa1369428c38d51460ab6fedff920efef932e/starlette-0.47.2.tar.gz", hash = "sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8", size = 2583948, upload-time = "2025-07-20T17:31:58.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/1f/b876b1f83aef204198a42dc101613fefccb32258e5428b5f9259677864b4/starlette-0.47.2-py3-none-any.whl", hash = "sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b", size = 72984, upload-time = "2025-07-20T17:31:56.738Z" }, + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, ] [[package]] @@ -1626,7 +1651,7 @@ wheels = [ [[package]] name = "typer" -version = "0.16.1" +version = "0.19.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1634,18 +1659,18 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/ea/9cc57c3c627fd7a6a0907ea371019fe74c3ec00e3cf209a6864140a602ad/typer-0.19.1.tar.gz", hash = "sha256:cb881433a4b15dacc875bb0583d1a61e78497806741f9aba792abcab390c03e6", size = 104802, upload-time = "2025-09-20T08:59:22.692Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, + { url = "https://files.pythonhosted.org/packages/1e/fa/6473c00b5eb26a2ba427813107699d3e6f4e1a4afad3f7494b17bdef3422/typer-0.19.1-py3-none-any.whl", hash = "sha256:914b2b39a1da4bafca5f30637ca26fa622a5bf9f515e5fdc772439f306d5682a", size = 46876, upload-time = "2025-09-20T08:59:21.153Z" }, ] [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] @@ -1671,30 +1696,54 @@ wheels = [ [[package]] name = "ujson" -version = "5.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/00/3110fd566786bfa542adb7932d62035e0c0ef662a8ff6544b6643b3d6fd7/ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1", size = 7154885, upload-time = "2024-05-14T02:02:34.233Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/a6/fd3f8bbd80842267e2d06c3583279555e8354c5986c952385199d57a5b6c/ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5", size = 55642, upload-time = "2024-05-14T02:01:04.055Z" }, - { url = "https://files.pythonhosted.org/packages/a8/47/dd03fd2b5ae727e16d5d18919b383959c6d269c7b948a380fdd879518640/ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e", size = 51807, upload-time = "2024-05-14T02:01:05.25Z" }, - { url = "https://files.pythonhosted.org/packages/25/23/079a4cc6fd7e2655a473ed9e776ddbb7144e27f04e8fc484a0fb45fe6f71/ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043", size = 51972, upload-time = "2024-05-14T02:01:06.458Z" }, - { url = "https://files.pythonhosted.org/packages/04/81/668707e5f2177791869b624be4c06fb2473bf97ee33296b18d1cf3092af7/ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1", size = 53686, upload-time = "2024-05-14T02:01:07.618Z" }, - { url = "https://files.pythonhosted.org/packages/bd/50/056d518a386d80aaf4505ccf3cee1c40d312a46901ed494d5711dd939bc3/ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3", size = 58591, upload-time = "2024-05-14T02:01:08.901Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d6/aeaf3e2d6fb1f4cfb6bf25f454d60490ed8146ddc0600fae44bfe7eb5a72/ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21", size = 997853, upload-time = "2024-05-14T02:01:10.772Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d5/1f2a5d2699f447f7d990334ca96e90065ea7f99b142ce96e85f26d7e78e2/ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2", size = 1140689, upload-time = "2024-05-14T02:01:12.214Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2c/6990f4ccb41ed93744aaaa3786394bca0875503f97690622f3cafc0adfde/ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e", size = 1043576, upload-time = "2024-05-14T02:01:14.39Z" }, - { url = "https://files.pythonhosted.org/packages/14/f5/a2368463dbb09fbdbf6a696062d0c0f62e4ae6fa65f38f829611da2e8fdd/ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e", size = 38764, upload-time = "2024-05-14T02:01:15.83Z" }, - { url = "https://files.pythonhosted.org/packages/59/2d/691f741ffd72b6c84438a93749ac57bf1a3f217ac4b0ea4fd0e96119e118/ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc", size = 42211, upload-time = "2024-05-14T02:01:17.567Z" }, - { url = "https://files.pythonhosted.org/packages/0d/69/b3e3f924bb0e8820bb46671979770c5be6a7d51c77a66324cdb09f1acddb/ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287", size = 55646, upload-time = "2024-05-14T02:01:19.26Z" }, - { url = "https://files.pythonhosted.org/packages/32/8a/9b748eb543c6cabc54ebeaa1f28035b1bd09c0800235b08e85990734c41e/ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e", size = 51806, upload-time = "2024-05-14T02:01:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/39/50/4b53ea234413b710a18b305f465b328e306ba9592e13a791a6a6b378869b/ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557", size = 51975, upload-time = "2024-05-14T02:01:21.904Z" }, - { url = "https://files.pythonhosted.org/packages/b4/9d/8061934f960cdb6dd55f0b3ceeff207fcc48c64f58b43403777ad5623d9e/ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988", size = 53693, upload-time = "2024-05-14T02:01:23.742Z" }, - { url = "https://files.pythonhosted.org/packages/f5/be/7bfa84b28519ddbb67efc8410765ca7da55e6b93aba84d97764cd5794dbc/ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816", size = 58594, upload-time = "2024-05-14T02:01:25.554Z" }, - { url = "https://files.pythonhosted.org/packages/48/eb/85d465abafb2c69d9699cfa5520e6e96561db787d36c677370e066c7e2e7/ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20", size = 997853, upload-time = "2024-05-14T02:01:27.151Z" }, - { url = "https://files.pythonhosted.org/packages/9f/76/2a63409fc05d34dd7d929357b7a45e3a2c96f22b4225cd74becd2ba6c4cb/ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0", size = 1140694, upload-time = "2024-05-14T02:01:29.113Z" }, - { url = "https://files.pythonhosted.org/packages/45/ed/582c4daba0f3e1688d923b5cb914ada1f9defa702df38a1916c899f7c4d1/ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f", size = 1043580, upload-time = "2024-05-14T02:01:31.447Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0c/9837fece153051e19c7bade9f88f9b409e026b9525927824cdf16293b43b/ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165", size = 38766, upload-time = "2024-05-14T02:01:32.856Z" }, - { url = "https://files.pythonhosted.org/packages/d7/72/6cb6728e2738c05bbe9bd522d6fc79f86b9a28402f38663e85a28fddd4a0/ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539", size = 42212, upload-time = "2024-05-14T02:01:33.97Z" }, +version = "5.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/d9/3f17e3c5773fb4941c68d9a37a47b1a79c9649d6c56aefbed87cc409d18a/ujson-5.11.0.tar.gz", hash = "sha256:e204ae6f909f099ba6b6b942131cee359ddda2b6e4ea39c12eb8b991fe2010e0", size = 7156583, upload-time = "2025-08-20T11:57:02.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/ef/a9cb1fce38f699123ff012161599fb9f2ff3f8d482b4b18c43a2dc35073f/ujson-5.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7895f0d2d53bd6aea11743bd56e3cb82d729980636cd0ed9b89418bf66591702", size = 55434, upload-time = "2025-08-20T11:55:34.987Z" }, + { url = "https://files.pythonhosted.org/packages/b1/05/dba51a00eb30bd947791b173766cbed3492269c150a7771d2750000c965f/ujson-5.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12b5e7e22a1fe01058000d1b317d3b65cc3daf61bd2ea7a2b76721fe160fa74d", size = 53190, upload-time = "2025-08-20T11:55:36.384Z" }, + { url = "https://files.pythonhosted.org/packages/03/3c/fd11a224f73fbffa299fb9644e425f38b38b30231f7923a088dd513aabb4/ujson-5.11.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0180a480a7d099082501cad1fe85252e4d4bf926b40960fb3d9e87a3a6fbbc80", size = 57600, upload-time = "2025-08-20T11:55:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/55/b9/405103cae24899df688a3431c776e00528bd4799e7d68820e7ebcf824f92/ujson-5.11.0-cp312-cp312-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:fa79fdb47701942c2132a9dd2297a1a85941d966d8c87bfd9e29b0cf423f26cc", size = 59791, upload-time = "2025-08-20T11:55:38.877Z" }, + { url = "https://files.pythonhosted.org/packages/17/7b/2dcbc2bbfdbf68f2368fb21ab0f6735e872290bb604c75f6e06b81edcb3f/ujson-5.11.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8254e858437c00f17cb72e7a644fc42dad0ebb21ea981b71df6e84b1072aaa7c", size = 57356, upload-time = "2025-08-20T11:55:40.036Z" }, + { url = "https://files.pythonhosted.org/packages/d1/71/fea2ca18986a366c750767b694430d5ded6b20b6985fddca72f74af38a4c/ujson-5.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1aa8a2ab482f09f6c10fba37112af5f957689a79ea598399c85009f2f29898b5", size = 1036313, upload-time = "2025-08-20T11:55:41.408Z" }, + { url = "https://files.pythonhosted.org/packages/a3/bb/d4220bd7532eac6288d8115db51710fa2d7d271250797b0bfba9f1e755af/ujson-5.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a638425d3c6eed0318df663df44480f4a40dc87cc7c6da44d221418312f6413b", size = 1195782, upload-time = "2025-08-20T11:55:43.357Z" }, + { url = "https://files.pythonhosted.org/packages/80/47/226e540aa38878ce1194454385701d82df538ccb5ff8db2cf1641dde849a/ujson-5.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e3cff632c1d78023b15f7e3a81c3745cd3f94c044d1e8fa8efbd6b161997bbc", size = 1088817, upload-time = "2025-08-20T11:55:45.262Z" }, + { url = "https://files.pythonhosted.org/packages/7e/81/546042f0b23c9040d61d46ea5ca76f0cc5e0d399180ddfb2ae976ebff5b5/ujson-5.11.0-cp312-cp312-win32.whl", hash = "sha256:be6b0eaf92cae8cdee4d4c9e074bde43ef1c590ed5ba037ea26c9632fb479c88", size = 39757, upload-time = "2025-08-20T11:55:46.522Z" }, + { url = "https://files.pythonhosted.org/packages/44/1b/27c05dc8c9728f44875d74b5bfa948ce91f6c33349232619279f35c6e817/ujson-5.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:b7b136cc6abc7619124fd897ef75f8e63105298b5ca9bdf43ebd0e1fa0ee105f", size = 43859, upload-time = "2025-08-20T11:55:47.987Z" }, + { url = "https://files.pythonhosted.org/packages/22/2d/37b6557c97c3409c202c838aa9c960ca3896843b4295c4b7bb2bbd260664/ujson-5.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:6cd2df62f24c506a0ba322d5e4fe4466d47a9467b57e881ee15a31f7ecf68ff6", size = 38361, upload-time = "2025-08-20T11:55:49.122Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ec/2de9dd371d52c377abc05d2b725645326c4562fc87296a8907c7bcdf2db7/ujson-5.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:109f59885041b14ee9569bf0bb3f98579c3fa0652317b355669939e5fc5ede53", size = 55435, upload-time = "2025-08-20T11:55:50.243Z" }, + { url = "https://files.pythonhosted.org/packages/5b/a4/f611f816eac3a581d8a4372f6967c3ed41eddbae4008d1d77f223f1a4e0a/ujson-5.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a31c6b8004438e8c20fc55ac1c0e07dad42941db24176fe9acf2815971f8e752", size = 53193, upload-time = "2025-08-20T11:55:51.373Z" }, + { url = "https://files.pythonhosted.org/packages/e9/c5/c161940967184de96f5cbbbcce45b562a4bf851d60f4c677704b1770136d/ujson-5.11.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78c684fb21255b9b90320ba7e199780f653e03f6c2528663768965f4126a5b50", size = 57603, upload-time = "2025-08-20T11:55:52.583Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d6/c7b2444238f5b2e2d0e3dab300b9ddc3606e4b1f0e4bed5a48157cebc792/ujson-5.11.0-cp313-cp313-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:4c9f5d6a27d035dd90a146f7761c2272cf7103de5127c9ab9c4cd39ea61e878a", size = 59794, upload-time = "2025-08-20T11:55:53.69Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a3/292551f936d3d02d9af148f53e1bc04306b00a7cf1fcbb86fa0d1c887242/ujson-5.11.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:837da4d27fed5fdc1b630bd18f519744b23a0b5ada1bbde1a36ba463f2900c03", size = 57363, upload-time = "2025-08-20T11:55:54.843Z" }, + { url = "https://files.pythonhosted.org/packages/90/a6/82cfa70448831b1a9e73f882225980b5c689bf539ec6400b31656a60ea46/ujson-5.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:787aff4a84da301b7f3bac09bc696e2e5670df829c6f8ecf39916b4e7e24e701", size = 1036311, upload-time = "2025-08-20T11:55:56.197Z" }, + { url = "https://files.pythonhosted.org/packages/84/5c/96e2266be50f21e9b27acaee8ca8f23ea0b85cb998c33d4f53147687839b/ujson-5.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6dd703c3e86dc6f7044c5ac0b3ae079ed96bf297974598116aa5fb7f655c3a60", size = 1195783, upload-time = "2025-08-20T11:55:58.081Z" }, + { url = "https://files.pythonhosted.org/packages/8d/20/78abe3d808cf3bb3e76f71fca46cd208317bf461c905d79f0d26b9df20f1/ujson-5.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3772e4fe6b0c1e025ba3c50841a0ca4786825a4894c8411bf8d3afe3a8061328", size = 1088822, upload-time = "2025-08-20T11:55:59.469Z" }, + { url = "https://files.pythonhosted.org/packages/d8/50/8856e24bec5e2fc7f775d867aeb7a3f137359356200ac44658f1f2c834b2/ujson-5.11.0-cp313-cp313-win32.whl", hash = "sha256:8fa2af7c1459204b7a42e98263b069bd535ea0cd978b4d6982f35af5a04a4241", size = 39753, upload-time = "2025-08-20T11:56:01.345Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/1baee0f4179a4d0f5ce086832147b6cc9b7731c24ca08e14a3fdb8d39c32/ujson-5.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:34032aeca4510a7c7102bd5933f59a37f63891f30a0706fb46487ab6f0edf8f0", size = 43866, upload-time = "2025-08-20T11:56:02.552Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8c/6d85ef5be82c6d66adced3ec5ef23353ed710a11f70b0b6a836878396334/ujson-5.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce076f2df2e1aa62b685086fbad67f2b1d3048369664b4cdccc50707325401f9", size = 38363, upload-time = "2025-08-20T11:56:03.688Z" }, + { url = "https://files.pythonhosted.org/packages/28/08/4518146f4984d112764b1dfa6fb7bad691c44a401adadaa5e23ccd930053/ujson-5.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:65724738c73645db88f70ba1f2e6fb678f913281804d5da2fd02c8c5839af302", size = 55462, upload-time = "2025-08-20T11:56:04.873Z" }, + { url = "https://files.pythonhosted.org/packages/29/37/2107b9a62168867a692654d8766b81bd2fd1e1ba13e2ec90555861e02b0c/ujson-5.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29113c003ca33ab71b1b480bde952fbab2a0b6b03a4ee4c3d71687cdcbd1a29d", size = 53246, upload-time = "2025-08-20T11:56:06.054Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f8/25583c70f83788edbe3ca62ce6c1b79eff465d78dec5eb2b2b56b3e98b33/ujson-5.11.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c44c703842024d796b4c78542a6fcd5c3cb948b9fc2a73ee65b9c86a22ee3638", size = 57631, upload-time = "2025-08-20T11:56:07.374Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ca/19b3a632933a09d696f10dc1b0dfa1d692e65ad507d12340116ce4f67967/ujson-5.11.0-cp314-cp314-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:e750c436fb90edf85585f5c62a35b35082502383840962c6983403d1bd96a02c", size = 59877, upload-time = "2025-08-20T11:56:08.534Z" }, + { url = "https://files.pythonhosted.org/packages/55/7a/4572af5324ad4b2bfdd2321e898a527050290147b4ea337a79a0e4e87ec7/ujson-5.11.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f278b31a7c52eb0947b2db55a5133fbc46b6f0ef49972cd1a80843b72e135aba", size = 57363, upload-time = "2025-08-20T11:56:09.758Z" }, + { url = "https://files.pythonhosted.org/packages/7b/71/a2b8c19cf4e1efe53cf439cdf7198ac60ae15471d2f1040b490c1f0f831f/ujson-5.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ab2cb8351d976e788669c8281465d44d4e94413718af497b4e7342d7b2f78018", size = 1036394, upload-time = "2025-08-20T11:56:11.168Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3e/7b98668cba3bb3735929c31b999b374ebc02c19dfa98dfebaeeb5c8597ca/ujson-5.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:090b4d11b380ae25453100b722d0609d5051ffe98f80ec52853ccf8249dfd840", size = 1195837, upload-time = "2025-08-20T11:56:12.6Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ea/8870f208c20b43571a5c409ebb2fe9b9dba5f494e9e60f9314ac01ea8f78/ujson-5.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:80017e870d882d5517d28995b62e4e518a894f932f1e242cbc802a2fd64d365c", size = 1088837, upload-time = "2025-08-20T11:56:14.15Z" }, + { url = "https://files.pythonhosted.org/packages/63/b6/c0e6607e37fa47929920a685a968c6b990a802dec65e9c5181e97845985d/ujson-5.11.0-cp314-cp314-win32.whl", hash = "sha256:1d663b96eb34c93392e9caae19c099ec4133ba21654b081956613327f0e973ac", size = 41022, upload-time = "2025-08-20T11:56:15.509Z" }, + { url = "https://files.pythonhosted.org/packages/4e/56/f4fe86b4c9000affd63e9219e59b222dc48b01c534533093e798bf617a7e/ujson-5.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:849e65b696f0d242833f1df4182096cedc50d414215d1371fca85c541fbff629", size = 45111, upload-time = "2025-08-20T11:56:16.597Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f3/669437f0280308db4783b12a6d88c00730b394327d8334cc7a32ef218e64/ujson-5.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:e73df8648c9470af2b6a6bf5250d4744ad2cf3d774dcf8c6e31f018bdd04d764", size = 39682, upload-time = "2025-08-20T11:56:17.763Z" }, + { url = "https://files.pythonhosted.org/packages/6e/cd/e9809b064a89fe5c4184649adeb13c1b98652db3f8518980b04227358574/ujson-5.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:de6e88f62796372fba1de973c11138f197d3e0e1d80bcb2b8aae1e826096d433", size = 55759, upload-time = "2025-08-20T11:56:18.882Z" }, + { url = "https://files.pythonhosted.org/packages/1b/be/ae26a6321179ebbb3a2e2685b9007c71bcda41ad7a77bbbe164005e956fc/ujson-5.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:49e56ef8066f11b80d620985ae36869a3ff7e4b74c3b6129182ec5d1df0255f3", size = 53634, upload-time = "2025-08-20T11:56:20.012Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e9/fb4a220ee6939db099f4cfeeae796ecb91e7584ad4d445d4ca7f994a9135/ujson-5.11.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a325fd2c3a056cf6c8e023f74a0c478dd282a93141356ae7f16d5309f5ff823", size = 58547, upload-time = "2025-08-20T11:56:21.175Z" }, + { url = "https://files.pythonhosted.org/packages/bd/f8/fc4b952b8f5fea09ea3397a0bd0ad019e474b204cabcb947cead5d4d1ffc/ujson-5.11.0-cp314-cp314t-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:a0af6574fc1d9d53f4ff371f58c96673e6d988ed2b5bf666a6143c782fa007e9", size = 60489, upload-time = "2025-08-20T11:56:22.342Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e5/af5491dfda4f8b77e24cf3da68ee0d1552f99a13e5c622f4cef1380925c3/ujson-5.11.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10f29e71ecf4ecd93a6610bd8efa8e7b6467454a363c3d6416db65de883eb076", size = 58035, upload-time = "2025-08-20T11:56:23.92Z" }, + { url = "https://files.pythonhosted.org/packages/c4/09/0945349dd41f25cc8c38d78ace49f14c5052c5bbb7257d2f466fa7bdb533/ujson-5.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a0a9b76a89827a592656fe12e000cf4f12da9692f51a841a4a07aa4c7ecc41c", size = 1037212, upload-time = "2025-08-20T11:56:25.274Z" }, + { url = "https://files.pythonhosted.org/packages/49/44/8e04496acb3d5a1cbee3a54828d9652f67a37523efa3d3b18a347339680a/ujson-5.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b16930f6a0753cdc7d637b33b4e8f10d5e351e1fb83872ba6375f1e87be39746", size = 1196500, upload-time = "2025-08-20T11:56:27.517Z" }, + { url = "https://files.pythonhosted.org/packages/64/ae/4bc825860d679a0f208a19af2f39206dfd804ace2403330fdc3170334a2f/ujson-5.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04c41afc195fd477a59db3a84d5b83a871bd648ef371cf8c6f43072d89144eef", size = 1089487, upload-time = "2025-08-20T11:56:29.07Z" }, + { url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" }, + { url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" }, ] [[package]] @@ -1708,15 +1757,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.35.0" +version = "0.36.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/5e/f0cd46063a02fd8515f0e880c37d2657845b7306c16ce6c4ffc44afd9036/uvicorn-0.36.0.tar.gz", hash = "sha256:527dc68d77819919d90a6b267be55f0e76704dca829d34aea9480be831a9b9d9", size = 80032, upload-time = "2025-09-20T01:07:14.418Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, + { url = "https://files.pythonhosted.org/packages/96/06/5cc0542b47c0338c1cb676b348e24a1c29acabc81000bced518231dded6f/uvicorn-0.36.0-py3-none-any.whl", hash = "sha256:6bb4ba67f16024883af8adf13aba3a9919e415358604ce46780d3f9bdc36d731", size = 67675, upload-time = "2025-09-20T01:07:12.984Z" }, ] [package.optional-dependencies]