added a bunch of content, a few new components

This commit is contained in:
John Doe 2021-04-24 01:02:22 -04:00
parent 2a8386e144
commit e87aae9d67
11 changed files with 1346 additions and 22 deletions

View file

@ -10,8 +10,11 @@
},
"dependencies": {
"compression": "^1.7.1",
"d3": "^6.7.0",
"polka": "next",
"sirv": "^1.0.0"
"satellite.js": "^4.1.3",
"sirv": "^1.0.0",
"topojson": "^3.0.2"
},
"devDependencies": {
"@babel/core": "^7.0.0",

View file

@ -0,0 +1,37 @@
<script>
export let title;
let hidden = true;
</script>
<div class="collapsedFAQ">
<div class="title" on:click={ ()=> {hidden = !hidden} }>
<div class="symbol">{hidden ? '+' : ''}</div> {title}
</div>
<div class="faqPoint" style="display: {hidden ? 'none' : 'block'}">
<slot />
</div>
</div>
<style>
.collapsedFAQ{
margin-top: 10px;
margin-bottom: 10px;
}
.symbol{
display: inline-block;
width: 1.0em;
}
.title{
color: #72bbd9;
cursor: pointer;
font-weight: bold;
user-select: none;
}
.faqPoint{
margin-bottom: 2.0em;
}
:global(.faqPoint p:first-child) {
margin-top: 0;
}
</style>

View file

@ -1,7 +1,7 @@
<div>
<div class="femtoHeader">
<svg
width="96"
height="75"
width="128"
height="100"
viewBox="0 0 32 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@ -15,15 +15,19 @@
fill="#FFFFFF"
/>
</svg>
<h1>FemtoStar</h1>
<h2>Satellite communications, done differently.</h2>
<div class="introText">
<p>
The FemtoStar Project is a global community developing a satellite
constellation for secure, open, and private communications - anywhere on
planet Earth.
</p>
</div>
</div>
<style>
div {
padding-top: 3em;
padding-bottom: 3em;
display: flex;
width: 100%;
background-color: #00111d;
@ -38,12 +42,16 @@
padding-top: 1em;
}
h1 {
h2 {
margin-top: 0.5em;
font-weight: bold;
}
h2 {
margin-top: -0.25em;
.introText {
width: 100%;
color: #ffffff;
}
p {
max-width: 512px;
}
</style>

View file

@ -1,19 +1,452 @@
<div class="globeContainer">
<img alt="placeholder for globe" src="https://via.placeholder.com/225" />
<svg id="globe" width="400" height="400"></svg>
<div class="globeText">
click and drag
</div>
</div>
<style>
.globeContainer {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
justify-content: center;
background-color: #00111d;
color: #ffffff;
}
img {
padding-right: 3em;
:global(.footprint--LEO) {
fill: rgba(255, 177, 64, 0.08);
stroke: rgba(255, 177, 64, 0.5);
}
.globeText{
text-align: center;
font-size: 0.6em;
color: #aaaaaa;
}
#globe {
display: block;
}
</style>
<script>
import * as d3 from "d3";
import * as sjs from 'satellite.js';
import { onMount } from 'svelte';
import tles from "../../static/tle.js"
import world110m from "../../static/world-110m.js"
import * as topojson from "topojson";
export let width = 300;
async function doThing() {
let satelliteJs = sjs;
var RADIANS = Math.PI / 180;
var DEGREES = 180 / Math.PI;
var R_EARTH = 6378.137; // equatorial radius (km)
/* =============================================== */
/* =============== CLOCK ========================= */
/* =============================================== */
/**
* Factory function for keeping track of elapsed time and rates.
*/
class Clock {
constructor() {
this._rate = 60; // 1ms elapsed : 60sec simulated
this._date = d3.now();
this._elapsed = 0;
}
async date(timeInMs) {
if (!arguments.length) return this._date + this._elapsed * this._rate;
this._date = timeInMs;
return this;
}
async elapsed(ms) {
if (!arguments.length) return this._date - d3.now(); // calculates elapsed
this._elapsed = ms;
return this;
}
async rate(secondsPerMsElapsed) {
if (!arguments.length) return this._rate;
this._rate = secondsPerMsElapsed;
return this;
}
}
/* ==================================================== */
/* =============== CONVERSION ========================= */
/* ==================================================== */
async function satrecToFeature(satrec, date, props) {
var properties = props || {};
var positionAndVelocity = satelliteJs.propagate(satrec, date);
var gmst = satelliteJs.gstime(date);
var positionGd = satelliteJs.eciToGeodetic(
positionAndVelocity.position,
gmst
);
properties.height = positionGd.height;
return {
type: "Feature",
properties: properties,
geometry: {
type: "Point",
coordinates: [
positionGd.longitude * DEGREES,
positionGd.latitude * DEGREES,
],
},
};
}
/* ==================================================== */
/* =============== TLE ================================ */
/* ==================================================== */
/**
* Factory function for working with TLE.
*/
class TLE {
constructor() {
this._properties;
this._date;
}
async _lines(arry) {
return arry.slice(0, 2);
}
async satrecs(tles) {
return tles.map(function (d) {
return satelliteJs.twoline2satrec.apply(null, this._lines(d));
});
}
async features(tles) {
var date = this._date || d3.now();
return tles.map(function (d) {
var satrec = satelliteJs.twoline2satrec.apply(null, this._lines(d));
return satrecToFeature(satrec, date, this._properties(d));
});
}
async lines(func) {
if (!arguments.length) return this._lines;
this._lines = func;
return this;
}
async properties(func) {
if (!arguments.length) return this._properties;
this._properties = func;
return this;
}
async date(ms) {
if (!arguments.length) return this._date;
this._date = ms;
return this;
}
}
/* ==================================================== */
/* =============== PARSE ============================== */
/* ==================================================== */
/**
* Parses text file string of tle into groups.
* @return {string[][]} Like [['tle line 1', 'tle line 2'], ...]
*/
async function parseTle(tleString) {
// remove last newline so that we can properly split all the lines
var lines = tleString.replace(/\r?\n$/g, "").split(/\r?\n/);
return lines.reduce(function (acc, cur, index) {
if (index % 2 === 0) acc.push([]);
acc[acc.length - 1].push(cur);
return acc;
}, []);
}
/* ==================================================== */
/* =============== SATELLITE ========================== */
/* ==================================================== */
/**
* Satellite factory function that wraps satellitejs functionality
* and can compute footprints based on TLE and date
*
* @param {string[][]} tle two-line element
* @param {Date} date date to propagate with TLE
*/
function Satellite(tle, date) {
this._satrec = satelliteJs.twoline2satrec(tle[0], tle[1]);
this._satNum = this._satrec.satnum; // NORAD Catalog Number
this._altitude; // km
this._position = {
lat: null,
lng: null,
};
this._halfAngle; // degrees
this._date;
this._gmst;
this.setDate(date);
this.update();
this._orbitType = this.orbitTypeFromAlt(this._altitude); // LEO, MEO, or GEO
}
/**
* Updates satellite position and altitude based on current TLE and date
*/
Satellite.prototype.update = async function () {
var positionAndVelocity = satelliteJs.propagate(this._satrec, this._date);
var positionGd = satelliteJs.eciToGeodetic(
positionAndVelocity.position,
this._gmst
);
this._position = {
lat: positionGd.latitude * DEGREES,
lng: positionGd.longitude * DEGREES,
};
this._altitude = positionGd.height;
return this;
};
/**
* @returns {GeoJSON.Polygon} GeoJSON describing the satellite's current footprint on the Earth
*/
Satellite.prototype.getFootprint = function () {
var theta = this._halfAngle * RADIANS;
let coreAngle = this._coreAngle(theta, this._altitude, R_EARTH) * DEGREES;
return d3
.geoCircle()
.center([this._position.lng, this._position.lat])
.radius(coreAngle)();
};
/**
* A conical satellite with half angle casts a circle on the Earth. Find the angle
* from the center of the earth to the radius of this circle
* @param {number} theta: Satellite half angle in radians
* @param {number} altitude Satellite altitude
* @param {number} r Earth radius
* @returns {number} core angle in radians
*/
Satellite.prototype._coreAngle = function (theta, altitude, r) {
// if FOV is larger than Earth, assume it goes to the tangential point
if (Math.sin(theta) > r / (altitude + r)) {
return Math.acos(r / (r + altitude));
}
return Math.abs(Math.asin(((r + altitude) * Math.sin(theta)) / r)) - theta;
};
Satellite.prototype.halfAngle = function (halfAngle) {
if (!arguments.length) return this._halfAngle;
this._halfAngle = halfAngle;
return this;
};
Satellite.prototype.satNum = function (satNum) {
if (!arguments.length) return this._satNum;
this._satNum = satNum;
return this;
};
Satellite.prototype.altitude = function (altitude) {
if (!arguments.length) return this._altitude;
this._altitude = altitude;
return this;
};
Satellite.prototype.position = function (position) {
if (!arguments.length) return this._position;
this._position = position;
return this;
};
Satellite.prototype.getOrbitType = function () {
return this._orbitType;
};
/**
* sets both the date and the Greenwich Mean Sidereal Time
* @param {Date} date
*/
Satellite.prototype.setDate = function (date) {
this._date = date;
this._gmst = satelliteJs.gstime(date);
return this;
};
/**
* Maps an altitude to a type of satellite
* @param {number} altitude (in KM)
* @returns {'LEO' | 'MEO' | 'GEO'}
*/
Satellite.prototype.orbitTypeFromAlt = function (altitude) {
this._altitude = altitude || this._altitude;
return this._altitude < 1200
? "LEO"
: this._altitude > 22000
? "GEO"
: "MEO";
};
/* =============================================== */
/* =================== GLOBE ===================== */
/* =============================================== */
// Approximate date the tle data was aquired from https://www.space-track.org/#recent
var TLE_DATA_DATE = new Date(2015, 11, 3, 17 ,36).getTime();
var activeClock;
var sats;
var svg = d3.select("#globe");
var marginTop = 0;
var width = svg.attr("width");
var height = svg.attr("height") - marginTop;
var projection = d3
.geoOrthographic()
.scale((height - 10) / 2)
.translate([width / 2, height / 2 + marginTop])
.rotate([45, -30]);
var geoPath = d3.geoPath().projection(projection);
svg
.append("path")
.datum({
type: "Sphere",
})
.style("cursor", "grab")
.attr("fill", "#2E86AB")
.attr("d", geoPath);
function initGlobe() {
let worldData = world110m;
svg
.selectAll(".segment")
.data([topojson.feature(worldData, worldData.objects.land)])
.enter()
.append("path")
.style("cursor", "grab")
.attr("class", "segment")
.attr("d", geoPath)
.style("stroke", "#88888800")
.style("stroke-width", "0px")
.style("fill", "#ffffff")
.style("opacity", "1");
}
async function updateSats(date) {
sats.forEach(async function (sat) {
return sat.setDate(date).update();
});
return sats;
}
/**
* Create satellite objects for each record in the TLEs and begin animation
* @param {string[][]} parsedTles
*/
async function initSats(parsedTles) {
activeClock = new Clock();
await activeClock.rate(100);
await activeClock.date(TLE_DATA_DATE);
sats = await Promise.all(
parsedTles.map(async function (tle) {
var sat = new Satellite(tle, new Date(2015, 11, 3, 17, 36));
sat.halfAngle(61.73);
return sat;
})
);
window.requestAnimationFrame(animateSats);
return sats;
}
async function draw() {
// redrawGlobe();
let allFootprints = svg.selectAll(".footprint");
let allFootprintsData = allFootprints.data(sats, async function (sat) {
return sat.satNum();
});
let allFootprintsDataJoin = allFootprintsData.join(function (enter) {
return enter
.append("path")
.attr("class", function (sat) {
return "footprint footprint--" + sat.getOrbitType();
})
.style("cursor", "grab");
});
allFootprintsDataJoin.attr("d", function (sat) {
return geoPath(sat.getFootprint());
});
}
async function redrawGlobe() {
let allSelectedSegment = svg.selectAll(".segment");
allSelectedSegment.attr("d", geoPath);
}
var m0;
var o0;
async function mousedown(e) {
m0 = [e.pageX, e.pageY];
o0 = projection.rotate();
e.preventDefault();
}
async function mousemove(e) {
if (m0) {
var m1 = [e.pageX, e.pageY];
const o1 = [o0[0] + (m1[0] - m0[0]) / 2.5, o0[1] + (m0[1] - m1[1]) / 2.5];
projection.rotate(o1);
redrawGlobe();
}
}
async function mouseup(e) {
if (m0) {
mousemove(e);
m0 = null;
}
}
svg.on("mousedown", mousedown);
d3.select(window).on("mousemove", mousemove).on("mouseup", mouseup);
async function animateSats(elapsed) {
var dateInMsI1 = await activeClock.elapsed(elapsed);
var dateInMs = dateInMsI1.date();
var date = new Date(await dateInMs);
updateSats(date);
draw();
window.requestAnimationFrame(animateSats);
}
initGlobe();
await initSats(await parseTle(tles))
}
onMount(async () => {
doThing();
});
</script>

View file

@ -11,6 +11,34 @@
href=".">home</a
>
</li>
<li>
<a
rel="prefetch"
aria-current={segment === "global-open-infrastructure" ? "page" : undefined}
href="./global-open-infrastructure">global open infrastructure</a
>
</li>
<li>
<a
rel="prefetch"
aria-current={segment === "privacy-by-design" ? "page" : undefined}
href="./privacy-by-design">privacy by design</a
>
</li>
<li>
<a
rel="prefetch"
aria-current={segment === "free-open-source" ? "page" : undefined}
href="./free-open-source">free and open-source</a
>
</li>
<li>
<a
rel="prefetch"
aria-current={segment === "faq" ? "page" : undefined}
href="./faq">faq</a
>
</li>
<li>
<a
rel="prefetch"

293
src/routes/faq.svelte Normal file
View file

@ -0,0 +1,293 @@
<script>
import FAQItem from "../components/FAQItem.svelte";
import TalkingPointContainer from "../components/TalkingPointContainer.svelte";
import TalkingPointContent from "../components/TalkingPointContent.svelte";
import TalkingPointName from "../components/TalkingPointName.svelte";
</script>
<svelte:head>
<title>FemtoStar - Global Open Infrastructure</title>
</svelte:head>
<div class="site">
<TalkingPointContainer>
<TalkingPointName text="Products and Services" />
<TalkingPointContent>
<FAQItem title="Do you plan to offer bandwidth tiers? Will there be a data cap?">
<p>All FemtoStar services are delivered on a best-effort basis, at the highest speed technically feasible with the user's hardware and with network
traffic at that time. We do not impose artificial restrictions on bandwidth. The flipside of this is that, while we do not limit you to a maximum
speed, we cannot guarantee you will always get one particular speed either - getting the maximum possible at all times means that, unlike a service
where you are constantly limited to a certain bandwidth even when more is possible, FemtoStar performance will vary. Performance at some times
being lower than at some others should be expected.</p>
<p>FemtoStar service is paid for in terms of the amount of beam time a session consumes - that is,
how long the satellite needs to spend using one of its beams to transmit data for that session. This is not the same as the amount of time a user
stays connected to the network - because the beam must also serve other users and any particular user's terminal is unlikely to be consuming the
full throughput of its link at all times, a connected terminal consumes much less beam time than the amount of time it remains connected, especially
when usage is light. What all of this means is that there is no data cap - we don't care about how many bytes you send through the satellite, only
how long the satellite must spend doing it.</p>
<p>This means that users with larger, higher-speed terminals (see the above point) able to transfer the
same amount of data in a shorter period of time will pay less for the same amount of data transferred, as they will consume less beam time in doing
so. Because beam time is the network's most important resource, and is the limiting factor in terms of network performance, we believe that charging
for service in terms of the actual resource - beam time - being consumed is the most fair model for service pricing.</p>
</FAQItem>
<FAQItem title="Who makes FemtoStar terminals?">
FemtoStar plans to take a hybrid approach to manufacturing and selling terminals. FemtoStar's higher-sales-volume "core" user terminals will be manufactured
and sold primarily by hardware partners, allowing us to leverage existing manufacturing and sales infrastructure. Meanwhile, development and reference
hardware, as well as more specialized terminals will be made in Canada by FemtoStar, at the same facility where we build our satellites. Every FemtoStar
terminal is based on FemtoStar-developed reference designs.
</FAQItem>
<FAQItem title="What speeds do you anticipate being available?">
<p>FemtoStar is a midband Mobile Satellite Service network, designed for speeds in line with other midband Mobile Satellite Service offerings.
Here, the term "midband" refers to the level of bandwidth between narrowband services, designed to provide a low-speed connection to small,
usually IoT/embedded terminals, and broadband services, designed to provide a high-speed connection to large, expensive, fixed terminals.</p>
<p>While this middle category of service may be unfamiliar to those more used to terrestrial services, it's common in the in Mobile Satellite
Service landscape, and is what's offered by services such as Inmarsat BGAN, Iridium Certus, or Thuraya IP. In these services, as in FemtoStar,
designing for this middle category means that users can expect performance much better than a narrowband system, while still having a portable
terminal much smaller than those needed for broadband systems. Like the aforementioned MSS options, a typical FemtoStar terminal should provide
in the mid-hundreds of kbps, using a terminal roughly the size of a tablet or small laptop.</p>
<p>Of course, FemtoStar's design still allows for
flexibility on the size and speed of terminals - users should be able to choose their own balance between speed, cost, and portability. As
such, depending on the size of the terminal, FemtoStar should be able to accomodate larger terminals in the megabits-per-second range, or
smaller terminals with reduced (if still better than typical narrowband offerings) speeds in a pocket-sized form factor.</p>
</FAQItem>
<FAQItem title="Is the FemtoStar Credit Token a cryptocurrency?">
<p>No, at least not by any usual definition of the term. While they are a digital system used to pay for service, and while they do make use of
cryptographic signatures for security, FemtoStar Credit Tokens are not transacted on a blockchain, cannot be mined, and are not intended
for use as anything other than payment for FemtoStar service. While third-party users are free to buy and sell Credit Tokens at any price
they are able to, their value in FemtoStar service is fixed.</p>
</FAQItem>
<FAQItem title="How do I buy FemtoStar tokens? Are they available yet?">
<p>Once our network is operational, you will be able to purchase FemtoStar tokens from FemtoStar via a retail token sales portal, from a
third-party reseller, in bulk from FemtoStar via a wholesale agreement, or from anyone else willing to sell them to you. While the FemtoStar
Project is capable of pre-issuing tokens that will be usable once the network is operational, we do not currently offer pre-issued retail
tokens to the general public, due to the inherent risk to consumers of purchasing a service before it is available. If you are interested in
working with us to purchase wholesale tokens, for resale as a token reseller or for a large deployment of FemtoStar hardware as an enterprise
user, please <a href="./about-contact">contact us</a>.</p>
</FAQItem>
</TalkingPointContent>
</TalkingPointContainer>
<TalkingPointContainer>
<TalkingPointName text="Network Architecture and Other Projects" />
<TalkingPointContent>
<FAQItem title="What about Starlink?">
<p><a href="https://starlink.com">Starlink</a> is a low-earth-orbit communications constellation developed by SpaceX. While we have a tremendous amount of
respect for the engineering accomplishments of the Starlink network, its goals and those of FemtoStar are almost entirely separate. While
both intend to provide satellite communications service using low-earth orbit constellations, Starlink is designed to provide consumer
broadband services to large, fixed terminals (in the satellite industry, this is known as Fixed Satellite Service). FemtoStar, on the
other hand, is designed for midband services to small and medium, portable or in-motion terminals (also known as Mobile Satellite Service).</p>
<p>
While the Starlink network is large, its architecture is traditional - it is designed to connect users to official ground stations providing
official services. While there has been talk of limited use of Starlink for point-to-point connectivity, such as for high-speed securities
trading, SpaceX holds complete control over use of this feature, and it is not a part of their consumer-facing services, nor is it known to
be possible with their consumer hardware. FemtoStar's open-infrastructure architecture ensures an inherently net-neutral network, wherein
all hardware is usable as a ground station, and even our own services are simply one of many a satellite is able to connect users to.</p>
<p>Starlink
terminals are uniquely identified on the network, and can be easily geolocated by the network (whether they report their GPS location is currently
unknown, but the network is certainly able to geolocate them accurately, as they are disallowed from accessing the network outside of the
small region, or "cell", where their user's address is registered). Starlink users are required to provide a substantial amount of personal
information in order to purchase service. Payments are handled on ground infrastructure, based on user accounts. FemtoStar does not require
any user account whatsoever, is not restricted to use in a small cell, and handles payments on the satellite itself using FemtoStar Credit Tokens.</p>
</FAQItem>
<FAQItem title="What about Blockstream or Othernet?">
<p><a href="https://blockstream.com">Blockstream</a> is a cryptocurrency company which offers a service named <a href="https://blockstream.com/satellite">Blockstream Satellite</a>.
<a href="https://othernet.is">Othernet</a> is a company which broadcasts data, primarily news and other text content, via satellite.</p>
<p>Blockstream Satellite broadcasts the Bitcoin blockchain, one-way, over six geostationary broadcasting satellites, and offers an API to transmit
your own short pieces of data over the network, with payment in Bitcoin. While Blockstream does allow for remote access to the Bitcoin blockchain,
it is a one-way system - it cannot be used for two-way communications, or to make online cryptocurrency transactions, unless you already have an internet
connection and can connect to its API.</p>
<p>Othernet provides one-way, broadcast data service via two geostationary satellites. This data typically consists of news, Wikipedia articles, and
other low-data-rate content which can be delivered one-way.</p>
<p>Both of these companies purchase time on existing geostationary broadcasting satellites, of the type typically used for consumer satellite television.
These services do not support, nor is the hardware provided for them capable of, any form of uplink from the user terminal. While both services are
useful as tools for broadcast data distribution, they are one-way, Broadcasting Satellite Service systems, distinct from two-way communications systems
in the Fixed Satellite Service (such as Starlink) and Mobile Satellite Service (such as FemtoStar).</p>
</FAQItem>
<FAQItem title="Are you sure satellites are the right way to do this? Surely a terrestrial network would be easier?">
<p>We're big fans of a number of the terrestrial privacy-respecting communications projects currently in development - in fact, FemtoStar <a href="./about-contact">began as a terrestrial
network</a>, named Private Mobile Data Protocol (PMDP).</p>
<p>The fundamental issue of terrestrial networks is the amount of hardware necessary to provide adequate coverage. It has taken decades of development,
thousands of licenses to thousands of companies in hundreds of countries, hundreds of billions of dollars at least, and <a href="https://www.mobileworldlive.com/blog/blog-global-base-station-count-7m-or-4-times-higher">more than 7 million cell
towers</a> to build mainstream cellular networks out to their current coverage, and even with this it's likely you still sometimes have problems
getting cellular service. We began with the assumption that a terrestrial network would be the only practical solution, and extensively tested
PMDP hardware in real-world urban and suburban environments. Eventually, even we - the developers of the technology - were forced to admit that
it was impractical without an impractically dense network, even for a small, urban implementation - letalone regional or global coverage.</p>
<p>As a thought experiment in community-run terrestrial networks, next time you leave home, ask yourself if you are ever more than 1 kilometer (3200 feet)
away from somewhere a mesh node or base station in a community-run terrestrial network could be installed without being removed, stolen, or
tampered with, and if anyone nearby would be willing to pay for, install, and maintain such a device. We tried this, with real hardware, in a real
city, in 2019, and came to the conclusion that that, in contrast to being an easier solution, it was likely outright impossible in most circumstances.</p>
<p>Where such networks can exist, they genuinely do have some advantages over satellite-based networks - however, in most places, it is simply not realistic to
build them. We found this out the hard way. It's also worth noting that FemtoStar can coexist with these networks symbiotically - where these networks can
be built, given that this is likely to occur in clusters of nodes or base stations (such as in a city center) separated by a substantial distance, we
believe FemtoStar could be extremely useful to link these sections together into larger, more resillient networks.</p>
</FAQItem>
<FAQItem title="What about mesh networks?">
<p>See the above point. While mesh networks are able to partially solve the problem of base station range by allowing every user device to extend coverage,
this still does not allow for coverage where there are no nodes. The same thought experiment applies - are you always within a kilometer of someone else
who might have a node in the mesh? If you have your own node in the mesh, is there ever another node nearby for it to mesh with? If not, a mesh network
may not be practical in your situation. Even where mesh networks are practical, FemtoStar could still be used to interconnect regions where the mesh is
available, even when they are separated by large regions with no nodes.</p>
</FAQItem>
<FAQItem title="I've used satellite internet, and the latency is pretty bad - is this true of FemtoStar too?">
<p>Not to nearly the same degree. While the distance to the satellite does add some amount of latency due to the time taken for the signal to reach the satellite,
the round-trip propagation time to a low-earth orbit satellite is a handful of milliseconds, not the hundreds of milliseconds familiar to users of geostationary
satellite networks. Ping time on FemtoStar should be less than a tenth of that which a geostationary satellite user would experience, if even that.</p>
</FAQItem>
<FAQItem title="How do you plan to mitigate orbital debris?">
<p>In contrast to the vast majority of small satellites, FemtoStar plans to include electric propulsion onboard our satellites, allowing them to be repositioned
as needed and cleanly deorbited at end-of-life. The FemtoStar Project is working closely with Applied Ion Systems, a leading developer of open-hardware
mallsat propulsion hardware, to develop a specialized implementation of their technology for use onboard the FemtoStar space vehicle. Even in the event of a thruster failure,
the solar panel can be positioned to drastically increase atmospheric drag on the satellite, rapidly increasing orbital decay and deorbiting the satellite.</p>
</FAQItem>
<FAQItem title="Is this a megaconstellation? How many satellites do you need?">
<p>The network can theoretically work with as little as a single satellite, however of course this configuration does not allow for continuous coverage.
Practical constellation layouts begin at around 48 satellites (and include the layout shown on our <a href="./">homepage</a>. We have also considered
the possibility of starting with a larger constellation of up to 96 satellites, however we believe the most reasonable approach would be to begin with
the minimum practical number of satellites (likely 48) and then scale up the constellation with new satellites as needed.</p>
</FAQItem>
<FAQItem title="What if a satellite fails? Will the network become unreliable?">
<p>The FemtoStar network provides multiple levels of protection against failure of spacecraft, and against failure of the network due to failure of a spacecraft,
resulting in a resilient network able to mitigate and work around hardware failures onboard satellites. Each satellite incorporates a degree of redundancy
previously seen only on far larger satellites, and is designed with longevity in mind. The network as a whole also protects against network-wide failure as
a result of the failure of a single satellite - most regions, especially those with a latitude near the inclination of the satellites such as North America
Europe, and Oceania, and much of Asia and South America - are covered redundantly, and even elsewhere, the "gap" caused when the only satellite visible to
a user has failed is short - lasting only minutes or less before working satellites come into view.</p>
<p>For most users, a satellite failure would likely be noticeable only as a decrease in the network's coverage angle, while for those in the aforementioned
near-inclination regions, it might not be noticeable at all. Finally, FemtoStar would be able to rapidly and inexpensively replenish its network with new satellites,
either newly-launched or simply moved into place if already available in a storage orbit.</p>
</FAQItem>
</TalkingPointContent>
</TalkingPointContainer>
<TalkingPointContainer>
<TalkingPointName text="Privacy and Security" />
<TalkingPointContent>
<FAQItem title="How is using FemtoStar private when using it indicates that you are looking for privacy?">
<p>FemtoStar is not purely a "privacy" system - we believe it to be competitive with other mobile satellite options, and in all likelihood there will be plenty
of FemtoStar users who aren't even aware of, much less interested in, its privacy features. We also believe there will be a number of FemtoStar terminals
installed as a part of machine-to-machine data installations, as backup connections for enterprise networks, or as backhaul to community-run terrestrial
networks. A user using it for privacy reasons is indistinguishable from any of these users.</p>
<p>Additionally, by this rationale, any privacy-respecting product, service, or system is bad for your privacy, as its use demonstrates that you are looking
for privacy. Even if your threat model truly does require that you obscure even the fact that someone is using a system that could be used for
privacy-respecting communications, FemtoStar still does substantially better than just about any other privacy-respecting communications network. For one thing, it uses
a substantially more directional antenna than any terrestrial mobile, which means its transmitted signal is very weak in any direction but that of the
satellite.</p>
<p>Its connection to the satellite is also is encrypted, and even to the satellite, it does not contain a location, terminal identifier, user account, or any
other identifying details. The terminal never transmits when it has no session open with the satellite, and, unlike mesh network nodes, it cannot be made
to transmit by the traffic of another user unless the terminal's owner has chosen to operate their own service over the network.</p>
</FAQItem>
<FAQItem title="Don't FemtoStar's satellites have to know where I am, based on which beam I use?">
<p>In theory, to some extent, but in practice, not meaningfully. In contrast to traditional communications satellites, a FemtoStar satellite, at least for
transmit, does not have a consistent beam pattern. Instead, electronic beamforming is used to point each of only a handful of beams, rapidly switching
beam patterns as the satellite jumps between active sessions. The footprints within which these beams are usable are hundreds of kilometers across,
even at their narrowest, and more than 2000 kilometers long. In addition, knowing where "you" are, as opposed to just knowing the rough area in which
one of the network's users is located, requires knowing who you are. As such, the satellite could determine that an anonymous session is within, for
example, northern Europe, western North America, or eastern Asia, but not that it is in a particular country or city, and certainly not who that
session belongs to.
</p>
</FAQItem>
<FAQItem title="You say geolocation-resistant - is it geolocation-proof?">
<p>We do not feel that we can promise that there is any two-way wireless communications system where it is truly impossible for an adversary to locate a
transmitter given enough time to search for it on the ground. In particular, it is extremely difficult to prevent just about any transmitter from
being detectable by a high-gain antenna at short range, no matter how directional or low-power the transmitter may be. However, we also believe
that such a search would need to begin relatively close to any terminal it wanted to have a chance of finding, and that it would likely be
complicated by the presence of more than one FemtoStar terminal in an area.</p>
<p>Additionally, there's the question of why finding terminals would be worthwhile to an attacker to begin with. Given that such an attack would almost
certainly involve the rather labor-intensive task of traveling around an area of interest with a vehicle full of equipment looking for terminals that
you cannot identify and cannot monitor the activity of, while also being unable to tell the difference between two intermittently-used terminals and
one terminal which has moved, we do feel we can say that this attack is unlikely to fit into many threat models.</p>
<p>A FemtoStar terminal can even be used as a receive-only device if this is acceptable for the user's use case - in this configuration, it would likely be
nearly impossible to geolocate, even with this sort of attack.</p>
<p>In short, we don't believe any transmitting device is truly geolocation-proof, but we do believe that geolocation of users can be made impractical for to
perform at a large scale, and that its value to an attacker can be substantially diminished. On top of this, we do feel we can safely say that FemtoStar
is substantially more geolocation-resistant than any currently-available two-way wireless communications system, and that it is likely that its
geolocation-resistance could only be matched or exceeded by another satellite-based system including most or all of the same geolocation-resistance features.</p>
</FAQItem>
<FAQItem title="What if the FemtoStar project is taken over by someone I don't trust?">
<p>The FemtoStar architecture does not require that you trust the FemtoStar Project, even to begin with. Because the user is not required to trust the FemtoStar
network, in order for the FemtoStar Project, or or an entity who had taken it over, to meaningfully compromise the security of FemtoStar users, many core
design elements of the network would need to be changed, necessitating, at minimum, a firmware update to user terminals to accomodate substantial protocol changes. A new update published without
<a href="./free-open-source">source code</a> would be immediately suspicious, as would a new update where the newly-released source code disabled privacy features.
</p>
</FAQItem>
<FAQItem title="FemtoStar Inc. is Canadian - what if I don't trust Canada?">
<p>See the above point. Even if a malicious governmen were to take over the FemtoStar Project and attempt to surveil its users, they would be
incapable of doing so without making changes that would be immediately obvious to users, and to our own developers in other countries. Additionally
FemtoStar Inc. in Canada is only one part of the overarching FemtoStar Project - we have developers all over the world.
</p>
</FAQItem>
<FAQItem title="What if the satellites themselves are attacked?">
<p>While we would never claim that it is impossible that a FemtoStar satellite could be compromised, either remotely or through physical attack, we believe
the likelihood of this to be low for a number of reasons.</p>
<p>The most important point here is that FemtoStar satellites are not especially useful targets to an attacker. Due to not being a trusted part of the network,
even if they themselves are fully compromised, they cannot be used to compromise FemtoStar users, nor would they be much use as part of a botnet, nor would
they provide an attacker with any additional utility in their intended purpose (communications) than is available officially.</p>
<p>With regards to compromising the satellites from the ground, the satellite's onboard software is subject to intense scrutiny, including through formal
proofs, makes extensive use of sandboxing, and, given the relative simplicity of the FemtoStar protocol, presents a small attack surface.</p>
<p>In terms of physical security, while FemtoStar's placement of its infrastructure in orbit certainly grants it a degree of inaccessibility compared to terrestrial
infrastructure, there are of course spacecraft which could conceivably reach a FemtoStar satellite, and could hypothetically either tamper with or replace it.
However, tampering would require physical capture and substantial disassembly of the satellite, which is detectable and would result in the deletion of onboard
keys, resulting in a tampered-with satellite being easily detectable from the ground (even if new software attempted to obscure this tampering), while a
replacement satellite would lack the cryptographic keys of the satellite it replaced entirely.</p>
<p>An attacker could opt to attempt to disable, capture, or destroy a satellite altogether - after all, if you want to assume that truly no adversary is off the table,
you could choose to consider even the use of anti-satellite weapons. However, an attacker trying to make the network truly unusable would need to destroy or disable
not just one satellite, but the entire constellation, and any replacement satellites, and to do so in a way which obscured their involvement, a daunting task
even for the largest possible adversaries. This type of attack is also immediately obvious (especially if the satellite is physically destroyed, resulting in
the generation of orbital debris), and even this still does not result in an actual compromise (geolocation, identification, etc.) of FemtoStar users.</p>
</FAQItem>
</TalkingPointContent>
</TalkingPointContainer>
</div>
<style>
.site {
padding-top: 1em;
padding-bottom: 3em;
max-width: 1500px;
margin-left: auto;
margin-right: auto;
}
</style>

View file

@ -16,7 +16,6 @@
<div class="container">
<Globe />
<FemtoHeader />
<IntroText />
</div>
</div>
@ -73,17 +72,19 @@
.site {
margin-left: auto;
margin-right: auto;
max-width: 1500px;
max-width: 1024px;
}
.hero {
margin-top: 3.0em;
margin-bottom: 3.0em;
background-color: aqua;
}
.hero .container {
background-color: aquamarine;
display: grid;
grid-template-columns: 30% auto 30%;
grid-template-columns: 400px auto;
grid-template-rows: auto;
}
</style>

96
static/tle.js Normal file
View file

@ -0,0 +1,96 @@
export default `1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 000.0000 0000000 000.0000 000.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 000.0000 0000000 000.0000 090.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 000.0000 0000000 000.0000 180.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 000.0000 0000000 000.0000 270.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 030.0000 0000000 000.0000 307.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 030.0000 0000000 000.0000 037.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 030.0000 0000000 000.0000 127.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 030.0000 0000000 000.0000 217.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 060.0000 0000000 000.0000 255.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 060.0000 0000000 000.0000 345.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 060.0000 0000000 000.0000 075.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 060.0000 0000000 000.0000 165.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 090.0000 0000000 000.0000 202.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 090.0000 0000000 000.0000 292.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 090.0000 0000000 000.0000 022.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 090.0000 0000000 000.0000 112.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 120.0000 0000000 000.0000 150.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 120.0000 0000000 000.0000 240.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 120.0000 0000000 000.0000 330.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 120.0000 0000000 000.0000 060.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 150.0000 0000000 000.0000 097.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 150.0000 0000000 000.0000 187.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 150.0000 0000000 000.0000 277.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 150.0000 0000000 000.0000 007.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 180.0000 0000000 000.0000 045.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 180.0000 0000000 000.0000 135.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 180.0000 0000000 000.0000 225.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 180.0000 0000000 000.0000 315.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 210.0000 0000000 000.0000 352.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 210.0000 0000000 000.0000 082.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 210.0000 0000000 000.0000 172.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 210.0000 0000000 000.0000 262.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 240.0000 0000000 000.0000 300.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 240.0000 0000000 000.0000 030.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 240.0000 0000000 000.0000 120.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 240.0000 0000000 000.0000 210.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 270.0000 0000000 000.0000 247.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 270.0000 0000000 000.0000 337.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 270.0000 0000000 000.0000 067.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 270.0000 0000000 000.0000 157.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 300.0000 0000000 000.0000 195.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 300.0000 0000000 000.0000 285.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 300.0000 0000000 000.0000 015.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 300.0000 0000000 000.0000 105.0000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 330.0000 0000000 000.0000 142.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 330.0000 0000000 000.0000 232.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 330.0000 0000000 000.0000 322.5000 14.12748000000000
1 00000U 00000A 00000.00000000 .00000000 00000-0 00000-0 0 0000
2 00000 53.0000 330.0000 0000000 000.0000 052.5000 14.12748000000000`

1
static/world-110m.js Normal file

File diff suppressed because one or more lines are too long

428
yarn.lock
View file

@ -1298,13 +1298,16 @@ __metadata:
"@rollup/plugin-replace": ^2.2.0
"@rollup/plugin-url": ^5.0.0
compression: ^1.7.1
d3: ^6.7.0
polka: next
rollup: ^2.3.4
rollup-plugin-svelte: ^7.0.0
rollup-plugin-terser: ^7.0.0
sapper: ^0.28.0
satellite.js: ^4.1.3
sirv: ^1.0.0
svelte: ^3.17.3
topojson: ^3.0.2
languageName: unknown
linkType: soft
@ -1621,7 +1624,7 @@ __metadata:
languageName: node
linkType: hard
"commander@npm:^2.19.0, commander@npm:^2.20.0":
"commander@npm:2, commander@npm:^2.19.0, commander@npm:^2.20.0":
version: 2.20.3
resolution: "commander@npm:2.20.3"
checksum: b73428e97de7624323f81ba13f8ed9271de487017432d18b4da3f07cfc528ad754bbd199004bd5d14e0ccd67d1fdfe0ec8dbbd4c438b401df3c4cc387bfd1daa
@ -1699,6 +1702,324 @@ __metadata:
languageName: node
linkType: hard
"d3-array@npm:2, d3-array@npm:>=2.5, d3-array@npm:^2.3.0":
version: 2.12.1
resolution: "d3-array@npm:2.12.1"
dependencies:
internmap: ^1.0.0
checksum: 3f7282474dcd2961abc3359eb45db8a1a0bcc379bbf2c5acd7efcbc772faccf55790f98569847d821b21f576b450bc826a762274a9ba64ec0f191fd1a652aedc
languageName: node
linkType: hard
"d3-axis@npm:2":
version: 2.1.0
resolution: "d3-axis@npm:2.1.0"
checksum: eebaf65b187906337d4fed09a1aac94c8929892dd7697fb01e80ae8de36c997979d717bb5a6be82769bc340bbba9cd378e15a350d516c26dc7dc206bab74cee0
languageName: node
linkType: hard
"d3-brush@npm:2":
version: 2.1.0
resolution: "d3-brush@npm:2.1.0"
dependencies:
d3-dispatch: 1 - 2
d3-drag: 2
d3-interpolate: 1 - 2
d3-selection: 2
d3-transition: 2
checksum: 90d78d6356ada62f6c9be7aa42716c05343b67ea438dd26f59dfea6648cd9be72e5029fdb2f1e71a2fbd51f72ecef03388729a0c7e38e8ca7e4a28548bb17d69
languageName: node
linkType: hard
"d3-chord@npm:2":
version: 2.0.0
resolution: "d3-chord@npm:2.0.0"
dependencies:
d3-path: 1 - 2
checksum: 9aa50edd1516522e5ad53fc4acf2c8f46f98c969f26ec72e04255ab970e84983461e775bf61bde7fcaff1cd4fb83d58c2d6c1629a22f90ffa2db390880dbfeb4
languageName: node
linkType: hard
"d3-color@npm:1 - 2, d3-color@npm:2":
version: 2.0.0
resolution: "d3-color@npm:2.0.0"
checksum: 637e1115981b7598d3f86418478e7bfc4939d23b48eecbf5ea2297048724e13e42dda60963cbf2ebe3866705fe2eb87fa27e529da55ad57cda16aa799747554d
languageName: node
linkType: hard
"d3-contour@npm:2":
version: 2.0.0
resolution: "d3-contour@npm:2.0.0"
dependencies:
d3-array: 2
checksum: a3b1facbee2e18246fc189e1f809f81e7046c325e4d1a1d029855648ad01043e104677914d044cf498b5488dcdb21ab62664a2669c3337c7974bf6aaec51c510
languageName: node
linkType: hard
"d3-delaunay@npm:5":
version: 5.3.0
resolution: "d3-delaunay@npm:5.3.0"
dependencies:
delaunator: 4
checksum: 834a9e3f04f3e69abec8cf5251fe34ff65c6cfd99802a271480cd46cfe0784b1f38bffde6c346c68b75446e64fccadd1beff82209b99d32f37a716131afe8966
languageName: node
linkType: hard
"d3-dispatch@npm:1 - 2, d3-dispatch@npm:2":
version: 2.0.0
resolution: "d3-dispatch@npm:2.0.0"
checksum: 6724fe8d3275d899f6a9208c7fca072bdeeee1de3e772cf3a15dac413dd42d94fa1d58f6e308910390a72f600e204035c042d138f962b44e4256632ec594abe6
languageName: node
linkType: hard
"d3-drag@npm:2":
version: 2.0.0
resolution: "d3-drag@npm:2.0.0"
dependencies:
d3-dispatch: 1 - 2
d3-selection: 2
checksum: 46bfb8bd95beb7c9c0e349d453a7b346d9bdf3fcad4667d90768c8f2cbdb8f7f3f4daaa5ef91575590f88c4032a5ec4972b8e0ad7c1d54862c0d9883a707dce7
languageName: node
linkType: hard
"d3-dsv@npm:1 - 2, d3-dsv@npm:2":
version: 2.0.0
resolution: "d3-dsv@npm:2.0.0"
dependencies:
commander: 2
iconv-lite: 0.4
rw: 1
bin:
csv2json: bin/dsv2json
csv2tsv: bin/dsv2dsv
dsv2dsv: bin/dsv2dsv
dsv2json: bin/dsv2json
json2csv: bin/json2dsv
json2dsv: bin/json2dsv
json2tsv: bin/json2dsv
tsv2csv: bin/dsv2dsv
tsv2json: bin/dsv2json
checksum: 44d138b8beb6e183ac0423775062cf49583603545276bb62dde24126698fb1d3c793e3c5217e4433b203f5c9e76af6919bf6c1fd9e623c34f6ea73d1ef107612
languageName: node
linkType: hard
"d3-ease@npm:1 - 2, d3-ease@npm:2":
version: 2.0.0
resolution: "d3-ease@npm:2.0.0"
checksum: 770df967fc54ef9c958966538688eab2c104188eb5a851072fc8e51e3191aa835f922f3249e8a11ecca60f35206801e5b429c8a0edd82b27323e69f821ba7d3f
languageName: node
linkType: hard
"d3-fetch@npm:2":
version: 2.0.0
resolution: "d3-fetch@npm:2.0.0"
dependencies:
d3-dsv: 1 - 2
checksum: 68d1967df5f57be9ee0c7269c3d601174d0646449736ebdad109b3831fe555386f32e5c2c65f3e944e3ecd093ce934005d564cd65793357839cfcc7619cfc35a
languageName: node
linkType: hard
"d3-force@npm:2":
version: 2.1.1
resolution: "d3-force@npm:2.1.1"
dependencies:
d3-dispatch: 1 - 2
d3-quadtree: 1 - 2
d3-timer: 1 - 2
checksum: d21df84e078e26e66662423020286ac1078130fea2545466fe2daa407a220e32cbc8dc3f51e4e2b93bd282841ab8819488e7d568251adca5a8c3a7474643264d
languageName: node
linkType: hard
"d3-format@npm:1 - 2, d3-format@npm:2":
version: 2.0.0
resolution: "d3-format@npm:2.0.0"
checksum: 515b8c3c407f6a73575c639eedd0470a659073d7c4f1f56b1b63c2a6a68d03543b7f9484bc351ac52d3a130c3768701952e000fe4d4c65bc3952c8beb6063768
languageName: node
linkType: hard
"d3-geo@npm:2":
version: 2.0.1
resolution: "d3-geo@npm:2.0.1"
dependencies:
d3-array: ">=2.5"
checksum: 62c9953e654d84316b57e3b6079604be40a6ee5a107bbf37c2e3802791bea91eff46bc886ef89b9e34a38f17146f9a061000c6d438fee2e36e96d800d5f4a611
languageName: node
linkType: hard
"d3-hierarchy@npm:2":
version: 2.0.0
resolution: "d3-hierarchy@npm:2.0.0"
checksum: 6fa4f8393444072c1466478e1baf1551857a6d6a797bbfb7b28bbe6322f288749ecdd6e1801b9c1978614c8a4664115aeda836dab8c8bd0829df75e6ac965f40
languageName: node
linkType: hard
"d3-interpolate@npm:1 - 2, d3-interpolate@npm:1.2.0 - 2, d3-interpolate@npm:2":
version: 2.0.1
resolution: "d3-interpolate@npm:2.0.1"
dependencies:
d3-color: 1 - 2
checksum: a996521ffaabceebaa241a3afc2787c9a0976c02491b806463778b962cabb72cfeb43d230b0cf7d3a9a25def85c6eefcad55ecb1b700cfbfa6344ce178bed478
languageName: node
linkType: hard
"d3-path@npm:1 - 2, d3-path@npm:2":
version: 2.0.0
resolution: "d3-path@npm:2.0.0"
checksum: 5b86ec5d29bb17ea76865cc3ec2028174e5614ffa9d8156535e55cf54aa9f47acb07735109242f3b58f0081526afbd1f343c6698de0b848068236b6dae9d5cb6
languageName: node
linkType: hard
"d3-polygon@npm:2":
version: 2.0.0
resolution: "d3-polygon@npm:2.0.0"
checksum: 346d4877cbab35fef84b79143bb4282e4fc8815f417f3ce3265b96d0283de77d2b82b4954101dba5b7f2429edc0f7f0c6c6d51b8bf3980f1d12b433a67473c01
languageName: node
linkType: hard
"d3-quadtree@npm:1 - 2, d3-quadtree@npm:2":
version: 2.0.0
resolution: "d3-quadtree@npm:2.0.0"
checksum: 2c1e2a29641b65d865239afca357b7bc58581e70d29b378718d3931ef71fe4f25d174569fbe4d7f09358252df1e1295254e09066a9f3e258a5878b0187230325
languageName: node
linkType: hard
"d3-random@npm:2":
version: 2.2.2
resolution: "d3-random@npm:2.2.2"
checksum: 82d2371007ce4446fbeea9fc728dc91930ff46c789aed03272fe0f770693c086dc0dcca4deb3f1ae40310fd65a3feb490a80bf21bd0dc03891e70b46881d1b6e
languageName: node
linkType: hard
"d3-scale-chromatic@npm:2":
version: 2.0.0
resolution: "d3-scale-chromatic@npm:2.0.0"
dependencies:
d3-color: 1 - 2
d3-interpolate: 1 - 2
checksum: 83a6edc33e784f1996d948901bb0776e71a7cf27d242c6bf080e6f0e0725c8236ef0d70756552f33ec0c8cb36f3ede98d0f0f69f6f3e434ab8d1cf1e1eec4d5f
languageName: node
linkType: hard
"d3-scale@npm:3":
version: 3.3.0
resolution: "d3-scale@npm:3.3.0"
dependencies:
d3-array: ^2.3.0
d3-format: 1 - 2
d3-interpolate: 1.2.0 - 2
d3-time: ^2.1.1
d3-time-format: 2 - 3
checksum: 2a22d0f5381ccb208a9d593b64db3a6f069ea928f132f042f0e12d5836ea5999f0f58b20c5aeddff96946deb277ed8d6ba3958e3330610e0ebaa6085f42baf9e
languageName: node
linkType: hard
"d3-selection@npm:2":
version: 2.0.0
resolution: "d3-selection@npm:2.0.0"
checksum: 9e6ef7ebf84f1c42bf0ff69c157f3f6f7991be7adc1fe1f56e71c4678a9a0c0143376265fca78edcaf2c69b15fa3dbd034be658ea5f0a81f86e7cd5837fcd05e
languageName: node
linkType: hard
"d3-shape@npm:2":
version: 2.1.0
resolution: "d3-shape@npm:2.1.0"
dependencies:
d3-path: 1 - 2
checksum: 64ef635f2107df6cd6abbac30e2a0accd3989c9930532688779bb4599dd74ca81f97879853c2db7fedbc0518596ea77452b25d01f30b04c9a3793175bb2255ef
languageName: node
linkType: hard
"d3-time-format@npm:2 - 3, d3-time-format@npm:3":
version: 3.0.0
resolution: "d3-time-format@npm:3.0.0"
dependencies:
d3-time: 1 - 2
checksum: 3e67e7eb5b8e1d0f31cc5b78bd5c4857d7fa59c0d9c1356b317e128095f93f8530c7046ccd903a3b8565268448596bc40ec0826df10f6dca9970a8b5faa0baab
languageName: node
linkType: hard
"d3-time@npm:1 - 2, d3-time@npm:2, d3-time@npm:^2.1.1":
version: 2.1.1
resolution: "d3-time@npm:2.1.1"
dependencies:
d3-array: 2
checksum: 4f90b2ba35de50e8cc436be0cd2c660b27261fdb9d75ce3c5a943f09de1bf27f8d01e1607c892174ccdeb26147f973593a38c80a8e20a007cbf071aece02086b
languageName: node
linkType: hard
"d3-timer@npm:1 - 2, d3-timer@npm:2":
version: 2.0.0
resolution: "d3-timer@npm:2.0.0"
checksum: 4e2ba2f02ec74bdb531c7cc974e59f51c2d7784331368b0af6b07f01f894c9de48d73b465280e6e54d9e85dca7c06de8f955764a312ce43caa8bfdf35db2917c
languageName: node
linkType: hard
"d3-transition@npm:2":
version: 2.0.0
resolution: "d3-transition@npm:2.0.0"
dependencies:
d3-color: 1 - 2
d3-dispatch: 1 - 2
d3-ease: 1 - 2
d3-interpolate: 1 - 2
d3-timer: 1 - 2
peerDependencies:
d3-selection: 2
checksum: a46e454e88a412e08061704fd84a32eeca64553b34646a5afa125b433d95f8428ccbb997c9055c74c901b5706065880462fb34b616f7d6e991473748226829fe
languageName: node
linkType: hard
"d3-zoom@npm:2":
version: 2.0.0
resolution: "d3-zoom@npm:2.0.0"
dependencies:
d3-dispatch: 1 - 2
d3-drag: 2
d3-interpolate: 1 - 2
d3-selection: 2
d3-transition: 2
checksum: 0cdd6526eb6482bf171be603d6410fc7a3992d1ef23250c6a1bcd239d13ead7f33d27a72f6ccf5a0a06071b7370745e6655009be00ca3f21e7d58c17f7c7e1fc
languageName: node
linkType: hard
"d3@npm:^6.7.0":
version: 6.7.0
resolution: "d3@npm:6.7.0"
dependencies:
d3-array: 2
d3-axis: 2
d3-brush: 2
d3-chord: 2
d3-color: 2
d3-contour: 2
d3-delaunay: 5
d3-dispatch: 2
d3-drag: 2
d3-dsv: 2
d3-ease: 2
d3-fetch: 2
d3-force: 2
d3-format: 2
d3-geo: 2
d3-hierarchy: 2
d3-interpolate: 2
d3-path: 2
d3-polygon: 2
d3-quadtree: 2
d3-random: 2
d3-scale: 3
d3-scale-chromatic: 2
d3-selection: 2
d3-shape: 2
d3-time: 2
d3-time-format: 3
d3-timer: 2
d3-transition: 2
d3-zoom: 2
checksum: 7573f0332b0b052b84cdf75dc8df3997fb35312fabf15954ed6c6d240421d6be32ee4859a4511bc17dcb0ba9fdfd0f3abcf490777e1c0ccf82f31b5f87ae4125
languageName: node
linkType: hard
"dashdash@npm:^1.12.0":
version: 1.14.1
resolution: "dashdash@npm:1.14.1"
@ -1752,6 +2073,13 @@ __metadata:
languageName: node
linkType: hard
"delaunator@npm:4":
version: 4.0.1
resolution: "delaunator@npm:4.0.1"
checksum: 0d7ba5ef6efaadccd0e17a01087f22f27a818279b9050d09032799052f59f0991d332f884a20ec9b839035077c732e6f894143d14207723c9b276c01a579d397
languageName: node
linkType: hard
"delayed-stream@npm:~1.0.0":
version: 1.0.0
resolution: "delayed-stream@npm:1.0.0"
@ -2088,6 +2416,15 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"iconv-lite@npm:0.4":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
dependencies:
safer-buffer: ">= 2.1.2 < 3"
checksum: a9b9521066ee81853a8561e92bd7240bc5d3b7d5ef7da807a475e7858b0246e318b6af518c30a20a8749ef5eafeaa9631079446e4e696c7b60f468b34dc2cbfc
languageName: node
linkType: hard
"inflight@npm:^1.0.4":
version: 1.0.6
resolution: "inflight@npm:1.0.6"
@ -2105,6 +2442,13 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"internmap@npm:^1.0.0":
version: 1.0.1
resolution: "internmap@npm:1.0.1"
checksum: 5d1b68dcf5d5cf2b01bc23015e9559d825da5718301c33bb4c2f6d84e43402520901e9794ace2a9d243352bcfcf1b2ad2337ff9527d266afd6a06c6405d9b920
languageName: node
linkType: hard
"is-core-module@npm:^2.2.0":
version: 2.2.0
resolution: "is-core-module@npm:2.2.0"
@ -2814,6 +3158,13 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"rw@npm:1":
version: 1.3.3
resolution: "rw@npm:1.3.3"
checksum: 8eb664ac5e5612d026e542cfdcb871f4705eb787032418fe1677e4bfa2e5afe4c2f1ffa4be0d4a30773645890424626744201fe10189a1993c43d3c5ec262ecb
languageName: node
linkType: hard
"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1":
version: 5.1.2
resolution: "safe-buffer@npm:5.1.2"
@ -2828,7 +3179,7 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0":
"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
checksum: 549ba83f5b314b59898efe3422120ce1ca7987a6eae5925a5fa5db930dc414d4a9dde0a5594f89638cd6ea60b6840ea961872908933ac2428d1726489db46fa5
@ -2853,6 +3204,13 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"satellite.js@npm:^4.1.3":
version: 4.1.3
resolution: "satellite.js@npm:4.1.3"
checksum: b6a061ae438242f2de5a3fd90d187401d8953c47e90072ef16341b84165d83c142ff573935ab2cc4c0b93540dda21d55dcad3d29f17a518f7d3ce0becb256a9f
languageName: node
linkType: hard
"semver@npm:7.0.0":
version: 7.0.0
resolution: "semver@npm:7.0.0"
@ -3096,6 +3454,72 @@ fsevents@~2.3.1:
languageName: node
linkType: hard
"topojson-client@npm:3":
version: 3.1.0
resolution: "topojson-client@npm:3.1.0"
dependencies:
commander: 2
bin:
topo2geo: bin/topo2geo
topomerge: bin/topomerge
topoquantize: bin/topoquantize
checksum: 189471a7436a511aae95ad21a078e2b46dbe50f9efd80321935455983bb9859155011b865d61ca4f0f57d34e97db7811a3be943c96c39ab58cd82c76a849f618
languageName: node
linkType: hard
"topojson-client@npm:3.0.0":
version: 3.0.0
resolution: "topojson-client@npm:3.0.0"
dependencies:
commander: 2
bin:
topo2geo: bin/topo2geo
topomerge: bin/topomerge
topoquantize: bin/topoquantize
checksum: e2b15ca6f7535da8c8c586549702193465860c22a48d120117674cd1b39d6618364a056c556ff8d3f988c2df3f3b5091f0ee556e94417fa8c1cd9110b9cfaf04
languageName: node
linkType: hard
"topojson-server@npm:3.0.0":
version: 3.0.0
resolution: "topojson-server@npm:3.0.0"
dependencies:
commander: 2
bin:
geo2topo: bin/geo2topo
checksum: e26d0aa98bd3c959991b3a6ca49656537421b03b8e35e520d6043504b2b4075d0987abf0978c5029a50e0e2cdede6e9de6d3198ec303984c52eceba6d9b725e5
languageName: node
linkType: hard
"topojson-simplify@npm:3.0.2":
version: 3.0.2
resolution: "topojson-simplify@npm:3.0.2"
dependencies:
commander: 2
topojson-client: 3
bin:
toposimplify: bin/toposimplify
checksum: b8eba42e00865629731cf18a7cc73c03d95fcc24f180c017de3badc3fae9874fd9703ad963b8cc85b90b43694b56df4166fb49fbc0598fa17e02df261f6838a6
languageName: node
linkType: hard
"topojson@npm:^3.0.2":
version: 3.0.2
resolution: "topojson@npm:3.0.2"
dependencies:
topojson-client: 3.0.0
topojson-server: 3.0.0
topojson-simplify: 3.0.2
bin:
geo2topo: node_modules/topojson-server/bin/geo2topo
topo2geo: node_modules/topojson-client/bin/topo2geo
topomerge: node_modules/topojson-client/bin/topomerge
topoquantize: node_modules/topojson-client/bin/topoquantize
toposimplify: node_modules/topojson-simplify/bin/toposimplify
checksum: bfce89b40c953e773d42290cda65d2062c33fa0db1af031c1198468f32cd46df6f6f43dcf5a45ebcc8200826117db2e2fd4dc523cc7228694bddd062fad0ed1c
languageName: node
linkType: hard
"totalist@npm:^1.0.0":
version: 1.1.0
resolution: "totalist@npm:1.1.0"