Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/autonoma.ca.git
calculators/README.md
+# Calculators
+
+The calculators use XML from the variables associated with the story. These
+XML variables are transformed into HTML using XSLT.
+
+# Requirements
+
+Software requirements include:
+
+* [yamlp](https://bitbucket.org/djarvis/yamlp/)
+* [go-yq](https://github.com/mikefarah/yq)
+* Java
+
+# Build
+
+Build a calculator as follows:
+
+``` bash
+IVARS=$HOME/writing/free-food/story/variables.yaml
+OVARS=variables.xml
+java -jar $HOME/bin/yamlp.jar --regex '(\{\{(.*?)\}\})' < "${IVARS}" | \
+ yq -o=xml - > "${OVARS}"
+```
+
+
calculators/calories/calculator.js
+/**
+ * The purpose of this code is to help calculate the energy production of
+ * a vertical farm. The energy production is contrasted with the energy
+ * consumption of a local population.
+ */
+
+/**
+ * Global for non-leap year.
+ */
+var DAYS_PER_YEAR = 365;
+
+/**
+ * Global for cent to dollar conversion.
+ */
+var CENTS_PER_DOLLAR = 100;
+
+$(document).ready( function() {
+ if( $.valHooks.text ) {
+ originalHook = $.valHooks.text.get;
+ }
+ else {
+ $.valHooks.text = {};
+ }
+
+ $.valHooks.text.get = function( el ) {
+ var result = parseFloat( el.value );
+ return isNaN( result ) ? el.value : result;
+ }
+
+ /**
+ * Recalculate the totals when an input value changes.
+ */
+ $(".variable").change( function() {
+ var building_tally = $("#building_tally").val();
+ var building_length = $("#building_length").val();
+ var building_width = $("#building_width").val();
+ var building_storeys = $("#building_storeys").val();
+
+ var building_infrastructure = $("#building_infrastructure").val();
+
+ // Crop area per storey.
+ var total_building_storey_area = Math.floor(
+ (building_length * building_width) * (1 - building_infrastructure) );
+
+ // Racks per storey.
+ var building_storey_height = $("#building_storey_height").val();
+ var crop_height = $("#crop_height").val();
+ var total_racks_per_storey =
+ Math.floor( building_storey_height / crop_height );
+ $("#total_racks_per_storey").val( total_racks_per_storey );
+
+ // Harvestable area per building.
+ var total_harvestable_area =
+ total_building_storey_area * building_storeys * total_racks_per_storey;
+
+ // Area per crop.
+ var crop_diameter = $("#crop_diameter").val();
+ var crop_area = Math.pow( (crop_diameter / 2), 2 ) * Math.PI;
+
+ // Plants per building.
+ var total_plants_per_building =
+ Math.floor( total_harvestable_area / crop_area );
+ $("#total_plants_per_building").val( total_plants_per_building );
+
+ // Energy per plant.
+ var crop_unit_energy = $("#crop_unit_energy").val();
+ var crop_units_per_plant = $("#crop_units_per_plant").val();
+
+ var total_energy_per_plant = crop_unit_energy * crop_units_per_plant;
+ $("#total_energy_per_plant").val( total_energy_per_plant );
+
+ // Energy per harvest.
+ var total_energy_per_harvest =
+ total_energy_per_plant * total_plants_per_building;
+ $("#total_energy_per_harvest").val( total_energy_per_harvest );
+
+ // Annual energy production.
+ var crop_harvests = $("#crop_harvests").val();
+ var total_energy_production =
+ total_energy_per_harvest * crop_harvests * building_tally;
+ $("#total_energy_production").val( total_energy_production );
+
+ // Annual energy consumption.
+ var people_population = $("#people_population").val();
+ var people_energy = $("#people_energy").val();
+
+ var total_energy_consumption =
+ people_population * people_energy * DAYS_PER_YEAR;
+ $("#total_energy_consumption").val( total_energy_consumption );
+
+ var lamp_coverage_fixture = $("#lamp_coverage_fixture").val();
+ var conveyer_ratio = $("#conveyer_ratio").val();
+
+ $("#total_area").val( total_harvestable_area );
+
+ // Number of lamps in fixed positions (without conveyance).
+ var lamps_fixed = total_harvestable_area / lamp_coverage_fixture;
+
+ // Number of lamps accounting for conveyance.
+ var lamps_moving = lamps_fixed - (conveyer_ratio * lamps_fixed);
+
+ $("#total_lamps").val( Math.ceil( lamps_moving ) );
+
+ // Number of conveyers required for the lamps.
+ var conveyers = lamps_fixed - lamps_moving;
+
+ $("#total_conveyers").val( Math.ceil( conveyers ) );
+
+ // Power consumption per lamp.
+ var lamp_power = $("#lamp_power").val();
+
+ // Total power required by all lamps.
+ var lamps_power = Math.ceil( lamps_moving * lamp_power );
+
+ $("#lamps_power").val( lamps_power );
+
+ // Power consumption per conveyer.
+ var conveyer_power = $("#conveyer_power").val();
+
+ // Total power required by all conveyers.
+ var conveyers_power = Math.ceil( conveyers * conveyer_power );
+
+ $("#conveyers_power").val( conveyers_power );
+
+ // Total power devoted to illumination.
+ var total_electric_consumption = Math.ceil( lamps_power + conveyers_power );
+
+ // Amount of wattage consumed.
+ $("#total_electric_consumption").val( total_electric_consumption );
+
+ var cost_kWh = $("#cost_kWh").val();
+ var cost_daily_usage = $("#cost_daily_usage").val();
+
+ var cost_per_hour = (total_electric_consumption / 1000) * cost_kWh;
+ var cost_per_day = cost_daily_usage * cost_per_hour;
+ var cost_per_year = cost_per_day * DAYS_PER_YEAR;
+
+ var total_electric_cost = Math.ceil( cost_per_year );
+
+ $("#total_electric_cost").val( total_electric_cost / CENTS_PER_DOLLAR );
+
+ // Display totals as comma-separated numbers.
+ // See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
+ $("#totals").find("input").each( function() {
+ if( $(this).val() ) {
+ $(this).val( $(this).val().toLocaleString() );
+ }
+ });
+ });
+
+ // Force totals calculation on page load.
+ $("#people_population").trigger( "change" );
+});
calculators/calories/calculator.min.js
+var DAYS_PER_YEAR=365,CENTS_PER_DOLLAR=100;
+$(document).ready(function(){$.valHooks.text?originalHook=$.valHooks.text.get:$.valHooks.text={};$.valHooks.text.get=function(b){var a=parseFloat(b.value);return isNaN(a)?b.value:a};$(".variable").change(function(){var b=$("#building_tally").val(),a=$("#building_length").val(),d=$("#building_width").val(),c=$("#building_storeys").val(),e=$("#building_infrastructure").val();a=Math.floor(a*d*(1-e));d=$("#building_storey_height").val();e=$("#crop_height").val();d=Math.floor(d/e);$("#total_racks_per_storey").val(d);
+c=a*c*d;a=$("#crop_diameter").val();a=Math.floor(c/(Math.pow(a/2,2)*Math.PI));$("#total_plants_per_building").val(a);d=$("#crop_unit_energy").val();e=$("#crop_units_per_plant").val();d*=e;$("#total_energy_per_plant").val(d);a*=d;$("#total_energy_per_harvest").val(a);d=$("#crop_harvests").val();b*=a*d;$("#total_energy_production").val(b);b=$("#people_population").val();a=$("#people_energy").val();b=b*a*DAYS_PER_YEAR;$("#total_energy_consumption").val(b);a=$("#lamp_coverage_fixture").val();b=$("#conveyer_ratio").val();
+$("#total_area").val(c);a=c/a;c=a-b*a;$("#total_lamps").val(Math.ceil(c));b=a-c;$("#total_conveyers").val(Math.ceil(b));a=$("#lamp_power").val();c=Math.ceil(c*a);$("#lamps_power").val(c);a=$("#conveyer_power").val();b=Math.ceil(b*a);$("#conveyers_power").val(b);b=Math.ceil(c+b);$("#total_electric_consumption").val(b);c=$("#cost_kWh").val();b=$("#cost_daily_usage").val()*(b/1E3)*c*DAYS_PER_YEAR;b=Math.ceil(b);$("#total_electric_cost").val(b/CENTS_PER_DOLLAR);$("#totals").find("input").each(function(){$(this).val()&&
+$(this).val($(this).val().toLocaleString())})});$("#people_population").trigger("change")});
calculators/calories/index.html
-
+<!DOCTYPE html><!DOCTYPE HTML><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1user-scalable=yes"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content="A hard sci-fi novel about automated food production, sentient machines, and surveillance societies."><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><title>autónoma</title><style media="screen" type="text/css">
+/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*# sourceMappingURL=normalize.min.css.map */
+ </style><link rel="stylesheet" type="text/css" media="screen" href="../../themes/simple.css"><link rel="stylesheet" type="text/css" media="screen" href="../../themes/form.css"><link rel="stylesheet" type="text/css" media="screen" href="../../themes/calculator.css"><link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:200|Libre+Baskerville" rel="stylesheet"></head><body><div class="page"><header class="section header"><h1>Vertical Farm Energy Calculator</h1></header><nav class="section menu"></nav><main class="section content"><p>
+ Food production calculator for renewable-powered vertical farms to
+ estimate local population sustenance requirements. Neither
+ nutritional requirements nor crop variety are considered.
+ </p><form id="calculator"><fieldset id="fieldset_people"><legend>People</legend><label for="people_population">
+ Population
+ </label><input tabindex="1" autofocus id="people_population" name="people_population" class="variable" type="number" step="any" min="0" value="1000"><label for="people_energy">
+ Daily Energy Requirements
+ (kJ)
+ </label><input tabindex="2" id="people_energy" name="people_energy" class="variable" type="number" step="any" min="0" value="8700"></fieldset><fieldset id="fieldset_building"><legend>Building</legend><label for="building_tally">
+ Tally
+ </label><input tabindex="3" id="building_tally" name="building_tally" class="variable" type="number" step="any" min="0" value="1"><label for="building_length">
+ Length
+ (m)
+ </label><input tabindex="4" id="building_length" name="building_length" class="variable" type="number" step="any" min="0" value="32"><label for="building_width">
+ Width
+ (m)
+ </label><input tabindex="5" id="building_width" name="building_width" class="variable" type="number" step="any" min="0" value="32"><label for="building_storey_height">
+ Storey Height
+ (m)
+ </label><input tabindex="6" id="building_storey_height" name="building_storey_height" class="variable" type="number" step="any" min="0" value="3"><label for="building_storeys">
+ Storeys
+ </label><input tabindex="7" id="building_storeys" name="building_storeys" class="variable" type="number" step="any" min="0" value="8"><label for="building_infrastructure">
+ Infrastructure (ratio)
+ </label><input tabindex="8" id="building_infrastructure" name="building_infrastructure" class="variable" type="number" step="any" min="0" value="0.3"></fieldset><fieldset id="fieldset_crop"><legend>
+ Crop (e.g., tomato)
+ </legend><label for="crop_height">
+ Height
+ (m)
+ </label><input tabindex="9" id="crop_height" name="crop_height" class="variable" type="number" step="any" min="0" value="1.5"><label for="crop_diameter">
+ Diameter
+ (m)
+ </label><input tabindex="10" id="crop_diameter" name="crop_diameter" class="variable" type="number" step="any" min="0" value="0.6"><label for="crop_unit_energy">
+ Unit Energy
+ (kJ)
+ </label><input tabindex="11" id="crop_unit_energy" name="crop_unit_energy" class="variable" type="number" step="any" min="0" value="338"><label for="crop_units_per_plant">
+ Units per Plant
+ </label><input tabindex="12" id="crop_units_per_plant" name="crop_units_per_plant" class="variable" type="number" step="any" min="0" value="50"><label for="crop_harvests">
+ Annual Harvests
+ </label><input tabindex="13" id="crop_harvests" name="crop_harvests" class="variable" type="number" step="any" min="0" value="5"></fieldset><fieldset id="fieldset_lamp"><legend>
+ Grow Lamp
+ </legend><label for="lamp_power">
+ Power
+ (W)
+ </label><input tabindex="14" id="lamp_power" name="lamp_power" class="variable" type="number" step="any" min="0" value="250"><label for="lamp_efficacy">
+ Luminous Efficacy
+ (lm/W)
+ </label><input tabindex="15" id="lamp_efficacy" name="lamp_efficacy" class="variable" type="number" step="any" min="0" value="303"><label for="lamp_length">
+ Length
+ (m)
+ </label><input tabindex="16" id="lamp_length" name="lamp_length" class="variable" type="number" step="any" min="0" value="1.22"><label for="lamp_width">
+ Width
+ (m)
+ </label><input tabindex="17" id="lamp_width" name="lamp_width" class="variable" type="number" step="any" min="0" value="0.28"><label for="lamp_height">
+ Height
+ (m)
+ </label><input tabindex="18" id="lamp_height" name="lamp_height" class="variable" type="number" step="any" min="0" value="0.17"><label for="lamp_coverage_fixture" title="Total area illuminated by a lamp">
+ Coverage
+ (m<sup>2</sup>)
+ </label><input tabindex="19" id="lamp_coverage_fixture" name="lamp_coverage_fixture" class="variable" type="number" step="any" min="0" value="1.2192"><label for="conveyer_ratio" title="Total area extended by a lamp mover">
+ Conveyance Ratio
+ </label><input tabindex="20" id="conveyer_ratio" name="conveyer_ratio" class="variable" type="number" step="any" min="0" value="0.35"><label for="conveyer_power" title="Electricity required for a lamp mover">
+ Conveyance Power
+ (W)
+ </label><input tabindex="21" id="conveyer_power" name="conveyer_power" class="variable" type="number" step="any" min="0" value="5"></fieldset><fieldset id="fieldset_costs"><legend>Electricity</legend><label for="cost_kWh">
+ Price
+ (¢/kWh)
+ </label><input tabindex="22" id="cost_kWh" name="cost_kWh" class="variable" type="number" step="any" min="0" value="11.27"><label for="cost_daily_usage">
+ Daily Usage
+ (hours/day)
+ </label><input tabindex="23" id="cost_daily_usage" name="cost_daily_usage" class="variable" type="number" step="any" min="1" value="12"></fieldset><fieldset id="totals"><legend>Totals</legend><div id="total_food" class="subtotal"><p>Food</p><label for="total_racks_per_storey">
+ Racks per Storey
+ </label><input type="text" value="" readonly id="total_racks_per_storey" name="total_racks_per_storey"><label for="total_plants_per_building">
+ Plants per Building
+ </label><input type="text" value="" readonly id="total_plants_per_building" name="total_plants_per_building"><label for="total_energy_per_plant">
+ Energy per Plant (kJ)
+ </label><input type="text" value="" readonly id="total_energy_per_plant" name="total_energy_per_plant"><label for="total_energy_per_harvest">
+ Energy per Harvest (kJ)
+ </label><input type="text" value="" readonly id="total_energy_per_harvest" name="total_energy_per_harvest"><label for="total_energy_production">
+ Annual Energy Production (kJ)
+ </label><input type="text" value="" readonly id="total_energy_production" name="total_energy_production"><label for="total_energy_consumption">
+ Annual Energy Consumption (kJ)
+ </label><input type="text" value="" readonly id="total_energy_consumption" name="total_energy_consumption"></div><div id="total_electricity" class="subtotal"><p>Illumination</p><label for="total_area">
+ Crop Area (m<sup>2</sup>)
+ </label><input type="text" value="" readonly id="total_area" name="total_area"><label for="total_lamps">
+ Lamps
+ </label><input type="text" value="" readonly id="total_lamps" name="total_lamps"><label for="lamps_power">
+ Lamps Power (W)
+ </label><input type="text" value="" readonly id="lamps_power" name="lamps_power"><label for="total_conveyers">
+ Conveyers
+ </label><input type="text" value="" readonly id="total_conveyers" name="total_conveyers"><label for="conveyers_power">
+ Conveyers Power (W)
+ </label><input type="text" value="" readonly id="conveyers_power" name="conveyers_power"><label for="total_electric_consumption">
+ Total Power Consumption (W)
+ </label><input type="text" value="" readonly id="total_electric_consumption" name="total_electric_consumption"><label for="total_electric_cost">
+ Annual Energy Cost ($)
+ </label><input type="text" value="" readonly id="total_electric_cost" name="total_electric_cost"></div></fieldset></form></main><footer class="section footer"></footer></div><script defer src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><script defer src="calculator.js"></script></body></html>
calculators/calories/index.xsl
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
+
+ <xsl:import href="../template.xsl" />
+
+ <xsl:template match="/root" mode="header">
+ <h1>Vertical Farm Energy Calculator</h1>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="content">
+ <p>
+ Food production calculator for renewable-powered vertical farms to
+ estimate local population sustenance requirements. Neither
+ nutritional requirements nor crop variety are considered.
+ </p>
+
+ <form id="calculator">
+ <fieldset id="fieldset_people">
+ <legend>People</legend>
+
+ <label for="people_population">
+ Population
+ </label>
+ <input tabindex="1" autofocus="autofocus"
+ id="people_population"
+ name="people_population"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/population/actual" />
+ </xsl:attribute>
+ </input>
+
+ <label for="people_energy">
+ Daily Energy Requirements
+ (<xsl:apply-templates select="farm/energy/unit" />)
+ </label>
+ <input tabindex="2"
+ id="people_energy"
+ name="people_energy"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/energy/value" />
+ </xsl:attribute>
+ </input>
+ </fieldset>
+
+ <fieldset id="fieldset_building">
+ <legend>Building</legend>
+
+ <label for="building_tally">
+ Tally
+ </label>
+ <input tabindex="3"
+ id="building_tally"
+ name="building_tally"
+ class="variable" type="number" step="any" min="0" value="1" />
+
+ <label for="building_length">
+ Length
+ (<xsl:apply-templates select="farm/building/length/unit" />)
+ </label>
+ <input tabindex="4"
+ id="building_length"
+ name="building_length"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/building/length/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="building_width">
+ Width
+ (<xsl:apply-templates select="farm/building/width/unit" />)
+ </label>
+ <input tabindex="5"
+ id="building_width"
+ name="building_width"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/building/width/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="building_storey_height">
+ Storey Height
+ (<xsl:apply-templates select="farm/building/storeys/height/unit" />)
+ </label>
+ <input tabindex="6"
+ id="building_storey_height"
+ name="building_storey_height"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/building/storeys/height/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="building_storeys">
+ Storeys
+ </label>
+ <input tabindex="7"
+ id="building_storeys"
+ name="building_storeys"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/building/storeys/total" />
+ </xsl:attribute>
+ </input>
+
+ <label for="building_infrastructure">
+ Infrastructure (ratio)
+ </label>
+ <input tabindex="8"
+ id="building_infrastructure"
+ name="building_infrastructure"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/building/interstitial" />
+ </xsl:attribute>
+ </input>
+ </fieldset>
+
+ <fieldset id="fieldset_crop">
+ <legend>
+ Crop (e.g., <xsl:apply-templates select="farm/crop/name" />)
+ </legend>
+
+ <label for="crop_height">
+ Height
+ (<xsl:apply-templates select="farm/crop/height/unit" />)
+ </label>
+ <input tabindex="9"
+ id="crop_height"
+ name="crop_height"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/crop/height/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="crop_diameter">
+ Diameter
+ (<xsl:apply-templates select="farm/crop/diameter/unit" />)
+ </label>
+ <input tabindex="10"
+ id="crop_diameter"
+ name="crop_diameter"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/crop/diameter/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="crop_unit_energy">
+ Unit Energy
+ (<xsl:apply-templates select="farm/crop/energy/unit" />)
+ </label>
+ <input tabindex="11"
+ id="crop_unit_energy"
+ name="crop_unit_energy"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/crop/energy/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="crop_units_per_plant">
+ Units per Plant
+ </label>
+ <input tabindex="12"
+ id="crop_units_per_plant"
+ name="crop_units_per_plant"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/crop/yield" />
+ </xsl:attribute>
+ </input>
+
+ <label for="crop_harvests">
+ Annual Harvests
+ </label>
+ <input tabindex="13"
+ id="crop_harvests"
+ name="crop_harvests"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/crop/harvests" />
+ </xsl:attribute>
+ </input>
+ </fieldset>
+
+ <fieldset id="fieldset_lamp">
+ <legend>
+ Grow Lamp
+ </legend>
+
+ <label for="lamp_power">
+ Power
+ (<xsl:apply-templates select="farm/lamp/power/unit" />)
+ </label>
+ <input tabindex="14"
+ id="lamp_power"
+ name="lamp_power"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/power/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="lamp_efficacy">
+ Luminous Efficacy
+ (<xsl:apply-templates select="farm/lamp/efficacy/unit" />)
+ </label>
+ <input tabindex="15"
+ id="lamp_efficacy"
+ name="lamp_efficacy"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/efficacy/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="lamp_length">
+ Length
+ (<xsl:apply-templates select="farm/lamp/length/unit" />)
+ </label>
+ <input tabindex="16"
+ id="lamp_length"
+ name="lamp_length"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/length/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="lamp_width">
+ Width
+ (<xsl:apply-templates select="farm/lamp/width/unit" />)
+ </label>
+ <input tabindex="17"
+ id="lamp_width"
+ name="lamp_width"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/width/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="lamp_height">
+ Height
+ (<xsl:apply-templates select="farm/lamp/height/unit" />)
+ </label>
+ <input tabindex="18"
+ id="lamp_height"
+ name="lamp_height"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/height/value" />
+ </xsl:attribute>
+ </input>
+
+ <label
+ for="lamp_coverage_fixture"
+ title="Total area illuminated by a lamp">
+ Coverage
+ (<xsl:apply-templates select="farm/lamp/coverage/fixture/unit" />)
+ </label>
+ <input tabindex="19"
+ id="lamp_coverage_fixture"
+ name="lamp_coverage_fixture"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/coverage/fixture/value" />
+ </xsl:attribute>
+ </input>
+
+ <label
+ for="conveyer_ratio"
+ title="Total area extended by a lamp mover">
+ Conveyance Ratio
+ </label>
+ <input tabindex="20"
+ id="conveyer_ratio"
+ name="conveyer_ratio"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/coverage/conveyance/ratio" />
+ </xsl:attribute>
+ </input>
+
+ <label
+ for="conveyer_power"
+ title="Electricity required for a lamp mover">
+ Conveyance Power
+ (<xsl:apply-templates select="farm/lamp/coverage/conveyance/power/unit" />)
+ </label>
+ <input tabindex="21"
+ id="conveyer_power"
+ name="conveyer_power"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/lamp/coverage/conveyance/power/value" />
+ </xsl:attribute>
+ </input>
+ </fieldset>
+
+ <fieldset id="fieldset_costs">
+ <legend>Electricity</legend>
+
+ <label for="cost_kWh">
+ Price
+ (<xsl:apply-templates select="farm/cost/electricity/unit" />)
+ </label>
+ <input tabindex="22"
+ id="cost_kWh"
+ name="cost_kWh"
+ class="variable" type="number" step="any" min="0">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/cost/electricity/value" />
+ </xsl:attribute>
+ </input>
+
+ <label for="cost_daily_usage">
+ Daily Usage
+ (<xsl:apply-templates select="farm/cost/electricity/usage/unit" />)
+ </label>
+ <input tabindex="23"
+ id="cost_daily_usage"
+ name="cost_daily_usage"
+ class="variable" type="number" step="any" min="1">
+
+ <xsl:attribute name="value">
+ <xsl:value-of select="farm/cost/electricity/usage/value" />
+ </xsl:attribute>
+ </input>
+ </fieldset>
+
+ <fieldset id="totals">
+ <legend>Totals</legend>
+
+ <div id="total_food" class="subtotal">
+ <p>Food</p>
+
+ <label for="total_racks_per_storey">
+ Racks per Storey
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_racks_per_storey" name="total_racks_per_storey" />
+
+ <label for="total_plants_per_building">
+ Plants per Building
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_plants_per_building" name="total_plants_per_building" />
+
+ <label for="total_energy_per_plant">
+ Energy per Plant (kJ)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_energy_per_plant" name="total_energy_per_plant" />
+
+ <label for="total_energy_per_harvest">
+ Energy per Harvest (kJ)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_energy_per_harvest" name="total_energy_per_harvest" />
+
+ <label for="total_energy_production">
+ Annual Energy Production (kJ)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_energy_production" name="total_energy_production" />
+
+ <label for="total_energy_consumption">
+ Annual Energy Consumption (kJ)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_energy_consumption" name="total_energy_consumption" />
+ </div>
+
+ <div id="total_electricity" class="subtotal">
+ <p>Illumination</p>
+
+ <label for="total_area">
+ Crop Area (m<sup>2</sup>)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_area" name="total_area" />
+
+ <label for="total_lamps">
+ Lamps
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_lamps" name="total_lamps" />
+
+ <label for="lamps_power">
+ Lamps Power (W)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="lamps_power" name="lamps_power" />
+
+ <label for="total_conveyers">
+ Conveyers
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_conveyers" name="total_conveyers" />
+
+ <label for="conveyers_power">
+ Conveyers Power (W)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="conveyers_power" name="conveyers_power" />
+
+ <label for="total_electric_consumption">
+ Total Power Consumption (W)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_electric_consumption" name="total_electric_consumption" />
+
+ <label for="total_electric_cost">
+ Annual Energy Cost ($)
+ </label>
+ <input
+ type="text" value="" readonly="readonly"
+ id="total_electric_cost" name="total_electric_cost" />
+ </div>
+ </fieldset>
+ </form>
+ </xsl:template>
+
+ <!-- Replace superscript encoded as ^# with <sup>#</sup>. -->
+ <xsl:template match="unit">
+ <xsl:value-of
+ select="replace( ., '\^(\d)', '&lt;sup>$1&lt;/sup>' )"
+ disable-output-escaping="yes" />
+ </xsl:template>
+
+ <xsl:template match="farm/crop/name">
+ <xsl:apply-templates />
+ </xsl:template>
+</xsl:stylesheet>
+
calculators/index.html
+<!DOCTYPE html><!DOCTYPE HTML><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1user-scalable=yes"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content="A hard sci-fi novel about automated food production, sentient machines, and surveillance societies."><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><title></title>
+</head>
+<body>
+<ul>
+<li><a href="rocket">Aerodynamic Heat Calculator</a></li>
+<li><a href="calories">Vertical Farm Energy Calculator</a></li>
+</ol>
+</body>
+</html>
calculators/rocket/aero/aero.js
+/**
+ * The purpose of this code is to help calculate parameters required to
+ * send a rocket into space using a combination of single-stage to orbit
+ * (SSO) and an electromagnetic accelerator.
+ */
+const GRAVITATIONAL_ACCELERATION = 0.10193679918451;
+
+// Shift magnitude
+const MAGNITUDE = 1000;
+
+// Convert from degrees C to K
+const CELSIUS_KELVIN = 273.15;
+
+// Specific gas constant for dry air
+const GAS_CONSTANT = 287.05;
+
+$(document).ready( function() {
+ const fn_val = $.fn.val;
+
+ /**
+ * Avoid duplicate calls to parseFloat by overriding jQuery's val().
+ */
+ $.fn.val = function( value ) {
+ // val() can be called with or without arguments: retain the behaviour.
+ const result = (arguments.length >= 1) ?
+ fn_val.call(this, value) : fn_val.call(this);
+
+ return parseFloat( result );
+ };
+
+ /**
+ * Recalculate the totals when an input value changes.
+ */
+ $(".variable").change( function() {
+ const accelerator_radius = $("#accelerator_radius").val();
+ const projectile_velocity = $("#projectile_velocity").val();
+ const rocket_mass = $("#rocket_mass").val();
+ const rocket_payload = $("#rocket_payload").val();
+ const rocket_drag = $("#rocket_drag").val();
+ const rocket_cross_section = $("#rocket_cross_section").val();
+ const fuel_mass = $("#fuel_mass").val();
+
+ // v^2
+ const velocity_2 = projectile_velocity * projectile_velocity;
+ // v^3
+ const velocity_3 = velocity_2 * projectile_velocity;
+
+ // Calculate maximum force exerted at peak acceleration.
+ const total_centrifugal_force = velocity_2 / accelerator_radius;
+ $("#total_centrifugal_force").val( total_centrifugal_force );
+
+ // Convert maximum force exerted at peak acceleration into G forces.
+ const total_centrifugal_force_g =
+ total_centrifugal_force * GRAVITATIONAL_ACCELERATION;
+ $("#total_centrifugal_force_g").val( total_centrifugal_force_g );
+
+ const atmosphere_altitude = $("#atmosphere_altitude").val();
+ const atmosphere_temperature = $("#atmosphere_temperature").val();
+ const atmosphere_sea_level = $("#atmosphere_sea_level").val();
+
+ const h = 0.0065 * atmosphere_altitude;
+ const t = CELSIUS_KELVIN + atmosphere_temperature;
+
+ // Calculate air pressure.
+ const total_air_pressure = atmosphere_sea_level * Math.pow(
+ 1 - (h / (h + t)), 5.257
+ );
+ $("#total_air_pressure").val( total_air_pressure );
+
+ // Calculate and convert air density into kilograms.
+ const total_air_density =
+ total_air_pressure / (GAS_CONSTANT * t);
+ $("#total_air_density").val( total_air_density );
+
+ // Calculate drag force.
+ const total_drag_force = 0.5
+ * total_air_density * velocity_2
+ * rocket_drag * rocket_cross_section;
+ $("#total_drag_force").val( total_drag_force );
+
+ // Compute total rocket mass.
+ const total_rocket_mass = rocket_mass + rocket_payload + fuel_mass;
+ $("#total_mass").val( total_rocket_mass );
+
+ // Compute total rocket dry mass.
+ const total_rocket_dry_mass = total_rocket_mass - fuel_mass;
+ $("#total_dry_mass").val( total_rocket_dry_mass );
+
+ // Calculate drag deceleration.
+ const total_deceleration = total_drag_force / total_rocket_mass;
+ $("#total_deceleration").val( total_deceleration );
+
+ // Convert drag deceleration into G forces.
+ const total_deceleration_g = total_deceleration * GRAVITATIONAL_ACCELERATION;
+ $("#total_deceleration_g").val( total_deceleration_g );
+
+ // 0.1 * 0.5 * (0.196 m^2) * (0.627 kg/m^3) * ((8000 m/s)^3)
+
+ // Calculate friction in megawatts.
+ const total_friction = 0.1 * rocket_drag * rocket_cross_section *
+ total_air_density * velocity_3 / MAGNITUDE / MAGNITUDE;
+ $("#total_friction").val( total_friction );
+
+ // Display totals as comma-separated numbers.
+ // See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
+ $("#totals").find("input").each( function() {
+ if( $(this).val() ) {
+ $(this).val( $(this).val().toLocaleString() );
+ }
+ });
+ });
+
+ // Force totals calculation on page load.
+ $("#rocket_height").trigger( "change" );
+});
calculators/rocket/aero/aero.min.js
+var GRAVITATIONAL_ACCELERATION=.10193679918451,MAGNITUDE=1E3,CELSIUS_KELVIN=273.15,GAS_CONSTANT=287.05;
+$(document).ready(function(){var k=$.fn.val;$.fn.val=function(a){var c=1<=arguments.length?k.call(this,a):k.call(this);return parseFloat(c)};$(".variable").change(function(){var a=$("#accelerator_radius").val(),c=$("#projectile_velocity").val(),e=$("#rocket_mass").val(),m=$("#rocket_payload").val(),f=$("#rocket_drag").val(),l=$("#rocket_cross_section").val(),b=$("#fuel_mass").val(),d=c*c;c*=d;a=d/a;$("#total_centrifugal_force").val(a);a*=GRAVITATIONAL_ACCELERATION;$("#total_centrifugal_force_g").val(a);
+var g=$("#atmosphere_altitude").val(),h=$("#atmosphere_temperature").val();a=$("#atmosphere_sea_level").val();g*=.0065;h=CELSIUS_KELVIN+h;a*=Math.pow(1-g/(g+h),5.257);$("#total_air_pressure").val(a);a/=GAS_CONSTANT*h;$("#total_air_density").val(a);d=.5*a*d*f*l;$("#total_drag_force").val(d);e=e+m+b;$("#total_mass").val(e);b=e-b;$("#total_dry_mass").val(b);b=d/e;$("#total_deceleration").val(b);b*=GRAVITATIONAL_ACCELERATION;$("#total_deceleration_g").val(b);f=.1*f*l*a*c/MAGNITUDE/MAGNITUDE;$("#total_friction").val(f);
+$("#totals").find("input").each(function(){$(this).val()&&$(this).val($(this).val().toLocaleString())})});$("#rocket_height").trigger("change")});
calculators/rocket/aero/index.html
+<!DOCTYPE HTML><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1user-scalable=yes"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content="A hard sci-fi novel about automated food production, sentient machines, and surveillance societies."><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><title>autónoma</title><style media="screen" type="text/css">
+/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*# sourceMappingURL=normalize.min.css.map */
+ </style><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/simple.css"><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/form.css"><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/calculator.css"><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.css"><link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:200|Libre+Baskerville" rel="stylesheet"></head><body><div class="page"><header class="section header"><h1>Aerodynamic Heat Calculator</h1></header><nav class="section menu"></nav><main class="section content"><p>
+ Helps determine skin surface temperature of a conical-nosed projectile
+ at various altitudes and velocities. Form field values are explained
+ in the <a href="#equations">Equations</a> section, below.
+ </p><form id="calculator"><fieldset id="fieldset_atmosphere"><legend>Atmosphere</legend><label for="atmosphere_sea_level">Sea Level Pressure (Pa)</label><input tabindex="1" autofocus class="variable" type="number" step="any" min="0" value="101325" id="atmosphere_sea_level" name="atmosphere_sea_level"><label for="atmosphere_temperature">Temperature (℃)</label><input tabindex="2" class="variable" type="number" step="0.1" min="-80" value="-7" id="atmosphere_temperature" name="atmosphere_temperature"><label for="atmosphere_altitude">Altitude (m)</label><input tabindex="3" class="variable" type="number" step="0.1" min="0" value="6268" id="atmosphere_altitude" name="atmosphere_altitude"></fieldset><fieldset id="fieldset_accelerator"><legend>Electromagnetic Accelerator Loop</legend><label for="accelerator_radius">Radius (m)</label><input tabindex="4" class="variable" type="number" step="0.1" min="0.1" value="5000" id="accelerator_radius" name="accelerator_radius"><label for="projectile_velocity">Projectile Exit Velocity (m/s)</label><input tabindex="5" class="variable" type="number" step="0.1" min="0" value="1000" id="projectile_velocity" name="projectile_velocity"></fieldset><fieldset id="fieldset_rocket"><legend>Rocket</legend><label for="rocket_height">Height (m)</label><input tabindex="6" class="variable" type="number" step="0.1" min="0" value="2" id="rocket_height" name="rocket_height"><label for="rocket_diameter">Diameter (m)</label><input tabindex="7" class="variable" type="number" step="0.1" min="0" value="0.5" id="rocket_diameter" name="rocket_diameter"><label for="rocket_mass">Body Mass (kg)</label><input tabindex="8" class="variable" type="number" step="0.1" min="0" value="700" id="rocket_mass" name="rocket_mass"><label for="rocket_payload">Payload (kg)</label><input tabindex="9" class="variable" type="number" step="0.01" min="0" value="6.25" id="rocket_payload" name="rocket_payload"><label for="rocket_cross_section">Cross-section (m<sup>2</sup>)</label><input tabindex="10" class="variable" type="number" step="any" min="0" value="0.196" id="rocket_cross_section" name="rocket_cross_section"><label for="rocket_drag">Coefficient of Drag</label><input tabindex="11" class="variable" type="number" step="any" min="0" value="0.4" id="rocket_drag" name="rocket_drag"></fieldset><fieldset id="fieldset_fuel"><legend>Fuel</legend><label for="fuel_mass">Mass (kg)</label><input tabindex="12" class="variable" type="number" step="0.1" min="0" value="300" id="fuel_mass" name="fuel_mass"><label for="fuel_specific_impulse">Specific Impulse (s)</label><input tabindex="13" class="variable" type="number" step="0.1" min="0" value="1700" id="fuel_specific_impulse" name="fuel_specific_impulse"></fieldset><fieldset id="totals"><legend class="totals">Total</legend><label for="total_mass">Launch Mass (kg)</label><input class="variable" type="text" value="" readonly id="total_mass" name="total_mass"><label for="total_dry_mass">Dry Mass (kg)</label><input class="variable" type="text" value="" readonly id="total_dry_mass" name="total_dry_mass"><label for="total_air_pressure">Air Pressure (Pa)</label><input class="variable" type="text" value="" readonly id="total_air_pressure" name="total_air_pressure"><label for="total_air_density">Air Density (kg/m<sup>3</sup>)</label><input class="variable" type="text" value="" readonly id="total_air_density" name="total_air_density"><label for="total_drag_force">Drag Force (N)</label><input class="variable" type="text" value="" readonly id="total_drag_force" name="total_drag_force"><label for="total_decleration">Drag Deceleration (m/s<sup>2</sup>)</label><input class="variable" type="text" value="" readonly id="total_deceleration" name="total_deceleration"><label for="total_decleration_g">Drag Deceleration (g-force)</label><input class="variable" type="text" value="" readonly id="total_deceleration_g" name="total_deceleration_g"><label for="total_centrifugal_force">Centrifugal Force (km/s<sup>2</sup>)</label><input class="variable" type="text" value="" readonly id="total_centrifugal_force" name="total_centrifugal_force"><label for="total_centrifugal_force_g">Centrifugal Force (g-force)</label><input class="variable" type="text" value="" readonly id="total_centrifugal_force_g" name="total_centrifugal_force_g"><label for="total_friction">Friction (MW)</label><input class="variable" type="text" value="" readonly id="total_friction" name="total_friction"></fieldset></form><a name="equations"></a><h1>Equations</h1><p>
+ This section describes equation inputs and outputs.
+ </p><h2>Centrifugal force</h2><p class="equation">
+ $$a = v^2 / r$$
+ $$g_{force} = 0.10193679918451 a$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd><dt>$r$</dt><dd>Accelerator loop radius (km)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$a$</dt><dd>Acceleration (km/s<sup>2</sup>)</dd><dt>$g_{force}$</dt><dd>Force experienced in terms of Earth's gravitational acceleration</dd></dl></div></div><h2>Cross-section area</h2><p class="equation">
+ $$A = \pi (d / 2)^2$$
+ </p><div class="variables"><div class="input"><h3>Input</h3><dl><dt>$d$</dt><dd>Rocket diameter (m)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$A$</dt><dd>Rocket's cross-section area (m<sup>2</sup>)</dd></dl></div></div><p>
+ A complete cross-section requires a far more complex calculation. The
+ value from that calculation can be provided as an input to the calculator.
+ </p><h2>Air pressure</h2><p class="equation">
+ $$P = P_{sea} \left(1 - \frac{0.0065 h}{0.0065 h + T + 273.15}\right)^{5.257}$$
+ </p><div class="variables"><div class="input"><h3>Input</h3><dl><dt>$h$</dt><dd>Altitude (m)</dd><dt>$T$</dt><dd>Temperature (°C)</dd><dt>$P_{sea}$</dt><dd>Sea level pressure (1013.25 hPa)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$P$</dt><dd>Air pressure (Pa)</dd></dl></div></div><h2>Air density</h2><p class="equation">
+ $$\rho = P / R (T + 273.15)$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$P$</dt><dd>Air pressure (Pa)</dd><dt>$R$</dt><dd>Specific gas constant for dry air (287.05&nbsp;J/(kg⋅K))</dd><dt>$T$</dt><dd>Temperature (°C)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$\rho$</dt><dd>Air density (kg/m<sup>3</sup>)</dd></dl></div></div><h2>Drag force</h2><p class="equation">
+ $$F_d = \frac{1}{2} \rho v^2 C_d A$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$\rho$</dt><dd>Air density (kg/m<sup>3</sup>)</dd><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd><dt>$C_d$</dt><dd>Coefficient of drag</dd><dt>$A$</dt><dd>Cross-section area (m<sup>2</sup>)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$F_d$</dt><dd>Drag force (kN)</dd></dl></div></div><h2>Drag deceleration</h2><p class="equation">
+ $$a_d = F_d / M$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$F_d$</dt><dd>Drag force (kN)</dd><dt>$M$</dt><dd>Mass (kg)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$a_d$</dt><dd>Drag deceleration (m/s<sup>2</sup>)</dd></dl></div></div><h2>Friction</h2><p class="equation">
+ $$F = 0.1 C_d A a_d v^3$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$C_d$</dt><dd>Coefficient of drag</dd><dt>$A$</dt><dd>Cross-section area (m<sup>2</sup>)</dd><dt>$a_d$</dt><dd>Drag deceleration (m/s<sup>2</sup>)</dd><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$F$</dt><dd>Heat experienced by rocket due to friction</dd></dl></div></div></main><footer class="section footer"></footer></div><script defer src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><script defer src="calculator.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/contrib/auto-render.min.js"></script><script>
+ renderMathInElement(
+ document.body, {
+ delimiters: [
+ { left: "$$", right: "$$", display: true },
+ { left: "\\[", right: "\\]", display: true },
+ { left: "$", right: "$", display: false },
+ { left: "\\(", right: "\\)", display: false }
+ ]
+ }
+ );
+ </script></body></html>
calculators/rocket/aero/index.xsl
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
+
+ <xsl:import href="../template.xsl" />
+
+ <xsl:template name="custom-stylesheet">
+ <link
+ rel="stylesheet"
+ href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.css" />
+ </xsl:template>
+
+ <xsl:template match="/root" mode="header">
+ <h1>Aerodynamic Heat Calculator</h1>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="content">
+ <p>
+ Helps determine skin surface temperature of a conical-nosed projectile
+ at various altitudes and velocities. Form field values are explained
+ in the <a href="#equations">Equations</a> section, below.
+ </p>
+
+ <form id="calculator">
+ <fieldset id="fieldset_atmosphere">
+ <legend>Atmosphere</legend>
+
+ <label for="atmosphere_sea_level">Sea Level Pressure (Pa)</label>
+ <input tabindex="1" autofocus="autofocus"
+ class="variable" type="number" step="any" min="0" value="101325"
+ id="atmosphere_sea_level" name="atmosphere_sea_level" />
+
+ <label for="atmosphere_temperature">Temperature (&#x2103;)</label>
+ <input tabindex="2"
+ class="variable" type="number" step="0.1" min="-80" value="-7"
+ id="atmosphere_temperature" name="atmosphere_temperature" />
+
+ <label for="atmosphere_altitude">Altitude (m)</label>
+ <input tabindex="3"
+ class="variable" type="number" step="0.1" min="0" value="6268"
+ id="atmosphere_altitude" name="atmosphere_altitude" />
+ </fieldset>
+
+ <fieldset id="fieldset_accelerator">
+ <legend>Electromagnetic Accelerator Loop</legend>
+
+ <label for="accelerator_radius">Radius (m)</label>
+ <input tabindex="4"
+ class="variable" type="number" step="0.1" min="0.1" value="5000"
+ id="accelerator_radius" name="accelerator_radius" />
+
+ <label for="projectile_velocity">Projectile Exit Velocity (m/s)</label>
+ <input tabindex="5"
+ class="variable" type="number" step="0.1" min="0" value="1000"
+ id="projectile_velocity" name="projectile_velocity" />
+ </fieldset>
+
+ <fieldset id="fieldset_rocket">
+ <legend>Rocket</legend>
+
+ <label for="rocket_height">Height (m)</label>
+ <input tabindex="6"
+ class="variable" type="number" step="0.1" min="0" value="2"
+ id="rocket_height" name="rocket_height" />
+
+ <label for="rocket_diameter">Diameter (m)</label>
+ <input tabindex="7"
+ class="variable" type="number" step="0.1" min="0" value="0.5"
+ id="rocket_diameter" name="rocket_diameter" />
+
+ <label for="rocket_mass">Body Mass (kg)</label>
+ <input tabindex="8"
+ class="variable" type="number" step="0.1" min="0" value="700"
+ id="rocket_mass" name="rocket_mass" />
+
+ <label for="rocket_payload">Payload (kg)</label>
+ <input tabindex="9"
+ class="variable" type="number" step="0.01" min="0" value="6.25"
+ id="rocket_payload" name="rocket_payload" />
+
+ <label for="rocket_cross_section">Cross-section (m<sup>2</sup>)</label>
+ <input tabindex="10"
+ class="variable" type="number" step="any" min="0" value="0.196"
+ id="rocket_cross_section" name="rocket_cross_section" />
+
+ <label for="rocket_drag">Coefficient of Drag</label>
+ <input tabindex="11"
+ class="variable" type="number" step="any" min="0" value="0.4"
+ id="rocket_drag" name="rocket_drag" />
+ </fieldset>
+
+ <fieldset id="fieldset_fuel">
+ <legend>Fuel</legend>
+
+ <label for="fuel_mass">Mass (kg)</label>
+ <input tabindex="12"
+ class="variable" type="number" step="0.1" min="0" value="300"
+ id="fuel_mass" name="fuel_mass" />
+
+ <label for="fuel_specific_impulse">Specific Impulse (s)</label>
+ <input tabindex="13"
+ class="variable" type="number" step="0.1" min="0" value="1700"
+ id="fuel_specific_impulse" name="fuel_specific_impulse" />
+ </fieldset>
+
+ <fieldset id="totals">
+ <legend
+ class="totals">Total</legend>
+
+ <label for="total_mass">Launch Mass (kg)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_mass" name="total_mass" />
+
+ <label for="total_dry_mass">Dry Mass (kg)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_dry_mass" name="total_dry_mass" />
+
+ <label for="total_air_pressure">Air Pressure (Pa)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_air_pressure" name="total_air_pressure" />
+
+ <label for="total_air_density">Air Density (kg/m<sup>3</sup>)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_air_density" name="total_air_density" />
+
+ <label for="total_drag_force">Drag Force (N)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_drag_force" name="total_drag_force" />
+
+ <label for="total_decleration">Drag Deceleration (m/s<sup>2</sup>)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_deceleration" name="total_deceleration" />
+
+ <label for="total_decleration_g">Drag Deceleration (g-force)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_deceleration_g" name="total_deceleration_g" />
+
+ <label for="total_centrifugal_force">Centrifugal Force (km/s<sup>2</sup>)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_centrifugal_force" name="total_centrifugal_force" />
+
+ <label for="total_centrifugal_force_g">Centrifugal Force (g-force)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_centrifugal_force_g" name="total_centrifugal_force_g" />
+
+ <label for="total_friction">Friction (MW)</label>
+ <input
+ class="variable" type="text" value="" readonly="readonly"
+ id="total_friction" name="total_friction" />
+ </fieldset>
+ </form>
+
+ <a name="equations" />
+ <h1>Equations</h1>
+ <p>
+ This section describes equation inputs and outputs.
+ </p>
+
+ <h2>Centrifugal force</h2>
+ <p class="equation">
+ $$a = v^2 / r$$
+ $$g_{force} = 0.10193679918451 a$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ <dt>$r$</dt>
+ <dd>Accelerator loop radius (km)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$a$</dt>
+ <dd>Acceleration (km/s<sup>2</sup>)</dd>
+ <dt>$g_{force}$</dt>
+ <dd>Force experienced in terms of Earth's gravitational acceleration</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Cross-section area</h2>
+ <p class="equation">
+ $$A = \pi (d / 2)^2$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Input</h3>
+ <dl>
+ <dt>$d$</dt>
+ <dd>Rocket diameter (m)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$A$</dt>
+ <dd>Rocket's cross-section area (m<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+ <p>
+ A complete cross-section requires a far more complex calculation. The
+ value from that calculation can be provided as an input to the calculator.
+ </p>
+
+ <h2>Air pressure</h2>
+ <p class="equation">
+ $$P = P_{sea} \left(1 - \frac{0.0065 h}{0.0065 h + T + 273.15}\right)^{5.257}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Input</h3>
+ <dl>
+ <dt>$h$</dt>
+ <dd>Altitude (m)</dd>
+ <dt>$T$</dt>
+ <dd>Temperature (&#x00b0;C)</dd>
+ <dt>$P_{sea}$</dt>
+ <dd>Sea level pressure (1013.25 hPa)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$P$</dt>
+ <dd>Air pressure (Pa)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Air density</h2>
+ <p class="equation">
+ $$\rho = P / R (T + 273.15)$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$P$</dt>
+ <dd>Air pressure (Pa)</dd>
+ <dt>$R$</dt>
+ <dd>Specific gas constant for dry air (287.05&#160;J/(kg⋅K))</dd>
+ <dt>$T$</dt>
+ <dd>Temperature (&#x00b0;C)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$\rho$</dt>
+ <dd>Air density (kg/m<sup>3</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Drag force</h2>
+ <p class="equation">
+ $$F_d = \frac{1}{2} \rho v^2 C_d A$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$\rho$</dt>
+ <dd>Air density (kg/m<sup>3</sup>)</dd>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ <dt>$C_d$</dt>
+ <dd>Coefficient of drag</dd>
+ <dt>$A$</dt>
+ <dd>Cross-section area (m<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$F_d$</dt>
+ <dd>Drag force (kN)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Drag deceleration</h2>
+ <p class="equation">
+ $$a_d = F_d / M$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$F_d$</dt>
+ <dd>Drag force (kN)</dd>
+ <dt>$M$</dt>
+ <dd>Mass (kg)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$a_d$</dt>
+ <dd>Drag deceleration (m/s<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Friction</h2>
+ <p class="equation">
+ $$F = 0.1 C_d A a_d v^3$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$C_d$</dt>
+ <dd>Coefficient of drag</dd>
+ <dt>$A$</dt>
+ <dd>Cross-section area (m<sup>2</sup>)</dd>
+ <dt>$a_d$</dt>
+ <dd>Drag deceleration (m/s<sup>2</sup>)</dd>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$F$</dt>
+ <dd>Heat experienced by rocket due to friction</dd>
+ </dl>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="custom-scripts">
+ <script
+ src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/katex.min.js" />
+ <script
+ src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/contrib/auto-render.min.js" />
+ <script>
+ renderMathInElement(
+ document.body, {
+ delimiters: [
+ { left: "$$", right: "$$", display: true },
+ { left: "\\[", right: "\\]", display: true },
+ { left: "$", right: "$", display: false },
+ { left: "\\(", right: "\\)", display: false }
+ ]
+ }
+ );
+ </script>
+ </xsl:template>
+
+</xsl:stylesheet>
+
calculators/rocket/cubesat.md
+CubeSat
+----
+Dimensions = 100 mm^3
+Mass = 1.33 kg
+
+Sentient Machine Brain
+----
+Dimensions = 300 mm^3
+Material = Titanium Dioxide
+Shape = Circle
+Pieces = 7
+Diamter = 30 cm
+Thickness = 1 mm
+Mass = 2.23133448 kg
+Calculator = https://www.twmetals.com/calculators.html
+
+Sentient Machine Brain CubeSat
+----
+Dimensions = 300 mm^3
+Payload = 4 kg + 2.2313348 kg = 6.2313348 kg ~= 6.25 kg
+
+Sentient Machine Rocket
+----
+Height = 2 m
+Diameter = 0.5 m
+Mass = 700 kg
+Chamber Material = Halfnium, nitrogen, and graphene
+Chamber Temperature = 5600 K
+Fuel Material = Metallic hydrogen
+Fuel Weight = 300 kg
+Specific Impulse = 1700 s
+
+Delta-V for LEO = 9,300 m/s
+Delta-V for Lunar = 16,400 km/s
+
+
calculators/rocket/payload/Earth.js
+class Earth {
+ static KELVIN = 273.15;
+ static STATIC_PRESSURE = 101325;
+ static TEMPERATURE_LAPSE_RATE = -0.0065;
+ static GAS_CONSTANT = 8.31432;
+ static GRAVITY = 9.80665;
+ static MOLAR_MASS_AIR = 0.0289644;
+ static MOLAR_MASS_DRY_AIR = 0.0289652;
+ static MOLAR_MASS_WATER_VAPOUR = 0.018016;
+ static RADIUS_EQUATOR = 6378137.0;
+ static RADIUS_POLAR = 6356752.0;
+ static MASS = 5.9722e24;
+ static SURFACE_GRAVITY = 9.780327;
+ static SIDEREAL_TIME = 86164.0905;
+ static SPEED_SOUND_0C = 331.3;
+ static GRAVITATIONAL_CONST = 6.67430e-11;
+ static STANDARD_GRAVITY = Earth.GRAVITATIONAL_CONST * Earth.MASS;
+
+ constructor(temperature, humidity) {
+ this.surface = temperature;
+ this.humidity = humidity / 100;
+ }
+
+ airPressure(altitude) {
+ return (
+ Earth.STATIC_PRESSURE *
+ Math.pow(
+ 1 +
+ (Earth.TEMPERATURE_LAPSE_RATE / this.kelvin(this.surface)) *
+ altitude,
+ (-Earth.GRAVITY * Earth.MOLAR_MASS_AIR) /
+ (Earth.GAS_CONSTANT * Earth.TEMPERATURE_LAPSE_RATE)
+ )
+ );
+ }
+
+ airDensity(altitude) {
+ const pressure = this.airPressure(altitude);
+ const kelvins = this.kelvin(this.surface);
+ const psat = 0.61078 * Math.exp(
+ (17.27 * (kelvins - Earth.KELVIN)) / (kelvins - 35.85)
+ );
+ const pressureVapour = this.humidity * psat;
+ const pressureDryAir = pressure - pressureVapour;
+
+ return (
+ (pressureDryAir / (Earth.MOLAR_MASS_DRY_AIR * kelvins)) +
+ (pressureVapour / (Earth.MOLAR_MASS_WATER_VAPOUR * kelvins))
+ );
+ }
+
+ kelvin(temperature) {
+ return temperature + Earth.KELVIN;
+ }
+
+ radians(degrees) {
+ return degrees * (Math.PI / 180);
+ }
+
+ radius(latitude) {
+ return (
+ Earth.RADIUS_EQUATOR *
+ (1 -
+ ((Earth.RADIUS_EQUATOR - Earth.RADIUS_POLAR) / Earth.RADIUS_EQUATOR) *
+ Math.pow(Math.sin(this.radians(latitude)), 2))
+ );
+ }
+
+ gravity(latitude, altitude) {
+ const radlat = this.radians(latitude);
+ const latitudeEffect = Math.sin(radlat) ** 2;
+ const shapeEffect = Math.sin(2 * radlat) ** 2;
+ const gravityVariation =
+ Earth.SURFACE_GRAVITY *
+ (1 + 0.0053024 * latitudeEffect - 0.0000058 * shapeEffect);
+ const altitudeCorrection = -3.086e-6 * altitude;
+
+ return gravityVariation + altitudeCorrection;
+ }
+
+ soundSpeed(altitude) {
+ const temperature = this.surface - (6 * altitude) / 1000;
+ return Earth.SPEED_SOUND_0C * Math.sqrt(1 + temperature / Earth.KELVIN);
+ }
+
+ rotationalSpeed(latitude) {
+ return this.radius(latitude) * (2 * Math.PI) / Earth.SIDEREAL_TIME;
+ }
+
+ orbitalSpeed(latitude, altitude) {
+ const distance = this.radius(latitude) + altitude;
+ return Math.sqrt(Earth.STANDARD_GRAVITY / distance);
+ }
+}
+
+export default Earth;
calculators/rocket/payload/FlightRecorder.js
+class FlightRecorder {
+ constructor() {
+ this.altitudes = new Telemetry('Altitude');
+ this.azimuths = new Telemetry('Azimuth');
+ this.horizontalVelocities = new Telemetry('Horizontal Velocity');
+ this.horizontalAccelerations = new Telemetry('Horizontal Acceleration');
+ this.verticalVelocities = new Telemetry('Vertical Velocity');
+ this.verticalAccelerations = new Telemetry('Vertical Acceleration');
+ this.masses = new Telemetry('Mass');
+ this.thrustAccelerations = new Telemetry('Thrust Acceleration');
+ }
+
+ altitude(time, value) {
+ this.altitudes.record(time, value);
+ }
+
+ azimuth(time, value) {
+ this.azimuths.record(time, value);
+ }
+
+ horizontalVelocity(time, value) {
+ this.horizontalVelocities.record(time, value);
+ }
+
+ horizontalAcceleration(time, value) {
+ this.horizontalAccelerations.record(time, value);
+ }
+
+ verticalVelocity(time, value) {
+ this.verticalVelocities.record(time, value);
+ }
+
+ verticalAcceleration(time, value) {
+ this.verticalAccelerations.record(time, value);
+ }
+
+ mass(time, value) {
+ this.masses.record(time, value);
+ }
+
+ thrustAcceleration(time, value) {
+ this.thrustAccelerations.record(time, value);
+ }
+
+ plot() {
+ this.azimuths.plot('Azimuth vs. Time', 'Azimuth (m)');
+ this.horizontalVelocities.plot('Horizontal Velocity vs. Time', 'Horizontal Velocity (m/s)');
+ this.horizontalAccelerations.plot('Horizontal Acceleration vs. Time', 'Horizontal Acceleration (m/s^2)');
+ this.altitudes.plot('Altitude vs. Time', 'Altitude (m)');
+ this.verticalVelocities.plot('Vertical Velocity vs. Time', 'Vertical Velocity (m/s)');
+ this.verticalAccelerations.plot('Vertical Acceleration vs. Time', 'Vertical Acceleration (m/s^2)');
+ this.thrustAccelerations.plot('Thrust Acceleration vs. Time', 'Thrust Acceleration (m/s^2)');
+ this.masses.plot('Mass vs. Time', 'Mass (kg)');
+ }
+}
+
+
calculators/rocket/payload/Rocket.js
+class Rocket {
+ constructor(wet, payload, diameter, dragCoefficient, specificImpulse) {
+ this.dry = wet * 0.1;
+ this.mass = wet;
+ this.targetMass = this.dry + this.payload;
+ this.payload = payload;
+ this.radius = diameter / 2.0;
+ this.specificImpulse = specificImpulse;
+ this.totalThrust = 0.0;
+
+ const crossSectionArea = Math.PI * Math.pow(this.radius, 2);
+ this.ballisticCoefficient = dragCoefficient * crossSectionArea;
+
+ this.flightRecorder = false;
+ this.launched = false;
+ this.relocated = false;
+ this.world = false;
+
+ this.massFlowRate = 0.0;
+ }
+
+ recorder(flightRecorder) {
+ this.blackBox = flightRecorder;
+ this.flightRecorder = true;
+ }
+
+ on(planet) {
+ this.planet = planet;
+ this.world = true;
+ }
+
+ translocate(latitude, altitude) {
+ console.assert(!this.launched);
+ console.assert(this.world);
+
+ this.latitude = latitude;
+ this.altitude = altitude;
+ this.azimuth = 0;
+
+ const LOCAL_GRAVITY = this.planet.gravity(latitude, altitude);
+ this.maxAcceleration = 5.0 * LOCAL_GRAVITY;
+ this.rotationalSpeed = this.planet.rotationalSpeed(latitude, altitude);
+ this.exhaustVelocity = this.specificImpulse * LOCAL_GRAVITY;
+ this.relocated = true;
+ }
+
+ launch(hVelocity, vVelocity) {
+ console.assert(!this.launched);
+
+ this.hVelocity = hVelocity + this.rotationalSpeed;
+ this.vVelocity = vVelocity;
+ this.launched = true;
+ }
+
+ apogee(altitude) {
+ this.targetVelocity = this.planet.orbitalSpeed(this.latitude, altitude);
+ }
+
+ drag() {
+ console.assert(this.launched);
+ console.assert(this.relocated);
+ console.assert(this.world);
+
+ const airDensity = this.planet.airDensity(this.altitude);
+ const netHorizontalVelocity = this.hVelocity - this.rotationalSpeed;
+ const totalSpeed = Math.sqrt(Math.pow(netHorizontalVelocity, 2) + Math.pow(this.vVelocity, 2));
+ const dragForceMagnitude = 0.5 * airDensity * this.ballisticCoefficient * Math.pow(totalSpeed, 2);
+ const forceRatio = [-netHorizontalVelocity / totalSpeed, -this.vVelocity / totalSpeed];
+
+ return [dragForceMagnitude * forceRatio[0], dragForceMagnitude * forceRatio[1]];
+ }
+
+ flying() {
+ return this.mass > this.targetMass;
+ }
+
+ below(altitude) {
+ return this.altitude < altitude;
+ }
+
+ fly(time) {
+ console.assert(time > 0);
+
+ this.totalThrust = this.exhaustVelocity * this.massFlowRate;
+
+ const dragForce = this.drag();
+ const thrusting = this.totalThrust > 0;
+ const vThrust = thrusting ? -dragForce[1] : 0.0;
+ const hThrust = thrusting ? Math.sqrt(Math.pow(this.totalThrust, 2) - Math.pow(vThrust, 2)) : 0.0;
+
+ this.hAcceleration = dragForce[0] / this.mass + hThrust / this.mass;
+ this.vAcceleration = dragForce[1] / this.mass + this.planet.gravity(this.latitude, this.altitude) + vThrust / this.mass;
+
+ // Records the initial values and all subsequent deltas.
+ this.record(time);
+
+ this.hVelocity += this.hAcceleration * time;
+ this.vVelocity += this.vAcceleration * time;
+
+ this.azimuth += this.hVelocity * time + 0.5 * this.hAcceleration * time * time;
+ this.altitude += this.vVelocity * time + 0.5 * this.vAcceleration * time * time;
+
+ this.mass -= this.massFlowRate * time;
+
+ if (this.hVelocity < this.targetVelocity) {
+ const accelerationMagnitude = Math.sqrt(
+ Math.pow(this.hAcceleration, 2) +
+ Math.pow(this.vAcceleration, 2)
+ );
+
+ const excessiveAcceleration = accelerationMagnitude > this.maxAcceleration;
+ const reducibleFlowRate = this.exhaustVelocity * this.massFlowRate * 0.98 > Math.abs(dragForce[1]);
+
+ if (excessiveAcceleration && reducibleFlowRate) {
+ this.massFlowRate *= 0.99;
+ }
+
+ if (this.exhaustVelocity * this.massFlowRate < Math.abs(dragForce[1])) {
+ this.massFlowRate = Math.abs(dragForce[1]) / this.exhaustVelocity * 1.1;
+ }
+ } else {
+ this.massFlowRate = 0.0;
+ }
+ }
+
+ record(time) {
+ console.assert(this.flightRecorder);
+
+ this.blackBox.azimuth(time, this.azimuth);
+ this.blackBox.horizontalVelocity(time, this.hVelocity);
+ this.blackBox.horizontalAcceleration(time, this.hAcceleration);
+ this.blackBox.altitude(time, this.altitude);
+ this.blackBox.verticalVelocity(time, this.vVelocity);
+ this.blackBox.verticalAcceleration(time, this.vAcceleration);
+ this.blackBox.thrustAcceleration(time, this.totalThrust / this.mass);
+ this.blackBox.mass(time, this.mass);
+ }
+}
+
+export default Rocket;
calculators/rocket/payload/Selector.js
+/**
+ * Provides a syntactic sugar for accessing client-side form fields.
+ */
+export function $(selector) {
+ const elements = document.querySelectorAll(selector);
+
+ if (elements.length === 1) {
+ return {
+ val: function (value) {
+ if (value !== undefined) {
+ elements[0].value = value;
+ } else {
+ return parseFloat(elements[0].value);
+ }
+ },
+ change: function (callback) {
+ elements[0].addEventListener('input', callback);
+ }
+ };
+ } else {
+ return {
+ change: function (callback) {
+ elements.forEach(function (element) {
+ element.addEventListener('input', callback);
+ });
+ }
+ };
+ }
+}
calculators/rocket/payload/Telemetry.js
+class Telemetry {
+ constructor(measureName) {
+ this.measureName = measureName;
+ this.times = [];
+ this.values = [];
+ }
+
+ record(time, value) {
+ this.times.push(time);
+ this.values.push(value);
+ }
+
+ plot(plotName, xLabel, yLabel) {
+ // TODO: Implement plotting logic using the chosen library
+ const data = {
+ x: this.times,
+ y: this.values
+ };
+
+ const layout = {
+ title: plotName,
+ xaxis: { title: 'Time (seconds)' },
+ yaxis: { title: yLabel }
+ };
+ }
+}
calculators/rocket/payload/index.html
-
+<!DOCTYPE html><!DOCTYPE HTML><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1user-scalable=yes"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="description" content="A hard sci-fi novel about automated food production, sentient machines, and surveillance societies."><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><style media="screen" type="text/css">
+/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*# sourceMappingURL=normalize.min.css.map */
+ </style><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/simple.css"><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/form.css"><link rel="stylesheet" type="text/css" media="screen" href="../../../themes/calculator.css"><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css"><link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:200|Libre+Baskerville" rel="stylesheet"></head><body><div class="page"><header class="section header"><h1>Orbital Launch Insertion</h1></header><nav class="section menu"></nav><main class="section content"><p>
+ Helps determine whether a payload can be inserted into a stable orbit.
+ Form field values are explained in the <a href="#equations">Equations</a>
+ section, below.
+ </p><form id="calculator"><fieldset id="environment"><legend>Environment</legend><label for="surface_temperature">Surface temperature (℃)</label><input tabindex="1" autofocus class="variable" type="number" step="1" min="-80" value="25" id="surface_temperature" name="surface_temperature"><label for="relative_humidity">Relative humidity</label><input tabindex="2" class="variable" type="number" step="0.01" min="0" value="86.34" id="surface_temperature" name="surface_temperature"></fieldset><fieldset id="mission"><legend>Mission</legend><label for="initial_velocity">Initial velocity (Mach)</label><input tabindex="3" class="variable" type="number" step="1" min="0" value="8" id="initial_velocity" name="initial_velocity"><label for="initial_latitude">Initial latitude (°)</label><input tabindex="4" class="variable" type="number" step="any" min="0" value="1.469167" id="initial_latitude" name="initial_latitude"><label for="initial_altitude">Initial altitude (m)</label><input tabindex="5" class="variable" type="number" step="1" min="0" value="6212" id="initial_altitude" name="initial_altitude"><label for="target_altitude">Target altitude (km)</label><input tabindex="6" class="variable" type="number" step="1" min="0" value="400" id="target_altitude" name="target_altitude"></fieldset><fieldset id="rocket"><legend>Rocket</legend><label for="diameter">Diameter (m)</label><input tabindex="7" class="variable" type="number" step="0.1" min="0" value="0.6" id="diameter" name="diameter"><label for="wet_mass">Wet mass (kg)</label><input tabindex="8" class="variable" type="number" step="1" min="0" value="250" id="wet_mass" name="wet_mass"><label for="payload">Payload mass (kg)</label><input tabindex="9" class="variable" type="number" step="1" min="1" value="25" id="payload_mass" name="payload_mass"><label for="drag_coefficient">Drag coefficient</label><input tabindex="10" class="variable" type="number" step="any" min="0" value="0.219" id="drag_coefficient" name="drag_coefficient"><label for="specific_impulse">Specific impulse (s)</label><input tabindex="11" class="variable" type="number" step="1" min="1" value="1700" id="specific_impulse" name="specific_impulse"></fieldset><button class="submit">Simulate</button><fieldset id="result"><legend>Result</legend></fieldset></form><a name="equations"></a><h1>Equations</h1><p>
+ This section describes equation inputs and outputs.
+ </p><h2>Centrifugal force</h2><p class="equation">
+ $$a = v^2 / r$$
+ $$g_{force} = 0.10193679918451 a$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd><dt>$r$</dt><dd>Accelerator loop radius (km)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$a$</dt><dd>Acceleration (km/s<sup>2</sup>)</dd><dt>$g_{force}$</dt><dd>Force experienced in terms of Earth's gravitational acceleration</dd></dl></div></div><h2>Cross-section area</h2><p class="equation">
+ $$A = \pi (d / 2)^2$$
+ </p><div class="variables"><div class="input"><h3>Input</h3><dl><dt>$d$</dt><dd>Rocket diameter (m)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$A$</dt><dd>Rocket's cross-section area (m<sup>2</sup>)</dd></dl></div></div><p>
+ A complete cross-section requires a far more complex calculation. The
+ value from that calculation can be provided as an input to the calculator.
+ </p><h2>Air pressure</h2><p class="equation">
+ $$P = P_{sea} \cdot \bigg[ 1 + \frac{L}{T} \cdot h \bigg] ^ {\frac{-g_0 \cdot M}{R \cdot L}}$$
+ </p><div class="variables"><div class="input"><h3>Input</h3><dl><dt>$P_{sea}$</dt><dd>Sea level pressure (101325&nbsp;Pa)</dd><dt>$L$</dt><dd>Lapse rate (-0.0065&nbsp;K/m)</dd><dt>$T$</dt><dd>Temperature (K)</dd><dt>$h$</dt><dd>Altitude (m)</dd><dt>$g_0$</dt><dd>Gravitational acceleration constant (9.80665&nbsp;m/s<sup>2</sup>)</dd><dt>$M$</dt><dd>Earth's atmospheric molar mass (0.0289644&nbsp;kg/mol)</dd><dt>$R$</dt><dd>Universal gas constant (8.31432&nbsp;N⋅m/mol⋅K)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$P$</dt><dd>Air pressure (Pa)</dd></dl></div></div><h2>Tetens equation</h2><p class="equation">
+ $$P_v = 0.61078 \cdot e ^ {17.27 \cdot T / (T + 237.31)}$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$T$</dt><dd>Temperature (℃)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$P_v$</dt><dd>Vapour pressure (Pa)</dd></dl></div></div><h2>Air density</h2><p class="equation">
+ $$\rho = \left(\frac{P_d}{R_d \cdot T}\right) + \left(\frac{P_v}{R_v \cdot T}\right)$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$P_d$</dt><dd>Partial pressure of dry air (Pa)</dd><dt>$P_v$</dt><dd>Partial pressure of water vapor (Pa)</dd><dt>$T$</dt><dd>Temperature (℃)</dd><dt>$R_d$</dt><dd>Specific gas constant for dry air (287.058&nbsp;J/(kg⋅K))</dd><dt>$R_v$</dt><dd>Specific gas constant for water vapour (461.495&nbsp;J/(kg⋅K))</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$\rho$</dt><dd>Air density (kg/m<sup>3</sup>)</dd></dl></div></div><h2>Earth radius</h2><p class="equation">
+ $$R_f = \frac{R_e - R_{pole}}{R_e}$$
+ $$R_E = R_e \cdot (1 - R_f \cdot sin^2 \phi)$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$R_e$</dt><dd>Equatorial radius (m)</dd><dt>$R_{pole}$</dt><dd>Polar radius (m)</dd><dt>$\phi$</dt><dd>Latitude (°)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$R_f$</dt><dd>Flattening ratio</dd><dt>$R_E$</dt><dd>Effective radius (m)</dd></dl></div></div><h2>Rotational speed</h2><p class="equation">
+ $$\omega = R_E(\varphi) \cdot \frac{2 \pi}{T_s}$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$R_E$</dt><dd>Effective radius (m)</dd><dt>$\varphi$</dt><dd>Latitude (°)</dd><dt>$T_s$</dt><dd>Sidereal time (86164.0905 s)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$\omega$</dt><dd>Rotational speed (m/s)</dd></dl></div></div><h2>Orbital speed</h2><p class="equation">
+ $$v_{orb} = \sqrt{\frac{g_0}{R_E(\varphi) + h}}$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$g_0$</dt><dd>Standard gravity (m/s<sup>2</sup>)</dd><dt>$R_E$</dt><dd>Effective radius (m)</dd><dt>$\varphi$</dt><dd>Latitude (°)</dd><dt>$h$</dt><dd>Altitude (m)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$v_{orb}$</dt><dd>Orbital speed (m/s)</dd></dl></div></div><h2>Gravity</h2><p class="equation">
+ $$g = g_0 \left(1 + 0.0053024 \cdot \sin^2(\varphi) - 0.0000058 \cdot \sin^2(2\varphi)\right) + \left(-3.086 \times 10^{-6} \cdot h\right)$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$g_0$</dt><dd>Surface gravity (m/s<sup>2</sup>)</dd><dt>$\varphi$</dt><dd>Latitude (°)</dd><dt>$h$</dt><dd>Altitude (m)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$g$</dt><dd>Gravity(m/s<sup>2</sup>)</dd></dl></div></div><h2>Speed of sound</h2><p class="equation">
+ $$cc = 331.3 \cdot \sqrt{1 + \frac{T_s - \left(\frac{6h}{1000}\right)}{273.15}}$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$T_s$</dt><dd>Surface temperature (℃)</dd><dt>$h$</dt><dd>Altitude (m)</dd></dl></div><div class="output"><h3>Outputs</h3><dl><dt>$cc$</dt><dd>Speed of sound (m/s)</dd></dl></div></div><h2>Drag force</h2><p class="equation">
+ $$F_d = \frac{1}{2} \rho v^2 C_d A$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$\rho$</dt><dd>Air density (kg/m<sup>3</sup>)</dd><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd><dt>$C_d$</dt><dd>Coefficient of drag</dd><dt>$A$</dt><dd>Cross-section area (m<sup>2</sup>)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$F_d$</dt><dd>Drag force (kN)</dd></dl></div></div><h2>Drag deceleration</h2><p class="equation">
+ $$a_d = F_d / M$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$F_d$</dt><dd>Drag force (kN)</dd><dt>$M$</dt><dd>Mass (kg)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$a_d$</dt><dd>Drag deceleration (m/s<sup>2</sup>)</dd></dl></div></div><h2>Friction</h2><p class="equation">
+ $$F = 0.1 C_d A a_d v^3$$
+ </p><div class="variables"><div class="input"><h3>Inputs</h3><dl><dt>$C_d$</dt><dd>Coefficient of drag</dd><dt>$A$</dt><dd>Cross-section area (m<sup>2</sup>)</dd><dt>$a_d$</dt><dd>Drag deceleration (m/s<sup>2</sup>)</dd><dt>$v$</dt><dd>Projectile exit velocity (km/s)</dd></dl></div><div class="output"><h3>Output</h3><dl><dt>$F$</dt><dd>Heat experienced by rocket due to friction</dd></dl></div></div></main><footer class="section footer"></footer></div><script defer src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><script defer src="calculator.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js"></script><script>
+ renderMathInElement(
+ document.body, {
+ delimiters: [
+ { left: "$$", right: "$$", display: true },
+ { left: "\\[", right: "\\]", display: true },
+ { left: "$", right: "$", display: false },
+ { left: "\\(", right: "\\)", display: false }
+ ]
+ }
+ );
+ </script></body></html>
calculators/rocket/payload/launch.xsl
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
+
+ <xsl:import href="../../template.xsl" />
+
+ <xsl:template name="custom-stylesheet">
+ <link
+ rel="stylesheet"
+ href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css" />
+ </xsl:template>
+
+ <xsl:template match="/root" mode="header">
+ <h1>Orbital Launch Insertion</h1>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="content">
+ <p>
+ Helps determine whether a payload can be inserted into a stable orbit.
+ Form field values are explained in the <a href="#equations">Equations</a>
+ section, below.
+ </p>
+
+ <form id="calculator">
+ <fieldset id="environment">
+ <legend>Environment</legend>
+ <label for="surface_temperature">Surface temperature (&#x2103;)</label>
+ <input tabindex="1" autofocus="autofocus"
+ class="variable" type="number" step="1" min="-80" value="25"
+ id="surface_temperature" name="surface_temperature" />
+
+ <label for="relative_humidity">Relative humidity</label>
+ <input tabindex="2"
+ class="variable" type="number" step="0.01" min="0" value="86.34"
+ id="surface_temperature" name="surface_temperature" />
+ </fieldset>
+
+ <fieldset id="mission">
+ <legend>Mission</legend>
+ <label for="initial_velocity">Initial velocity (Mach)</label>
+ <input tabindex="3"
+ class="variable" type="number" step="1" min="0" value="8"
+ id="initial_velocity" name="initial_velocity" />
+
+ <label for="initial_latitude">Initial latitude (&#x00b0;)</label>
+ <input tabindex="4"
+ class="variable" type="number" step="any" min="0" value="1.469167"
+ id="initial_latitude" name="initial_latitude" />
+
+ <label for="initial_altitude">Initial altitude (m)</label>
+ <input tabindex="5"
+ class="variable" type="number" step="1" min="0" value="6212"
+ id="initial_altitude" name="initial_altitude" />
+
+ <label for="target_altitude">Target altitude (km)</label>
+ <input tabindex="6"
+ class="variable" type="number" step="1" min="0" value="400"
+ id="target_altitude" name="target_altitude" />
+ </fieldset>
+
+ <fieldset id="rocket">
+ <legend>Rocket</legend>
+ <label for="diameter">Diameter (m)</label>
+ <input tabindex="7"
+ class="variable" type="number" step="0.1" min="0" value="0.6"
+ id="diameter" name="diameter" />
+
+ <label for="wet_mass">Wet mass (kg)</label>
+ <input tabindex="8"
+ class="variable" type="number" step="1" min="0" value="250"
+ id="wet_mass" name="wet_mass" />
+
+ <label for="payload">Payload mass (kg)</label>
+ <input tabindex="9"
+ class="variable" type="number" step="1" min="1" value="25"
+ id="payload_mass" name="payload_mass" />
+
+ <label for="drag_coefficient">Drag coefficient</label>
+ <input tabindex="10"
+ class="variable" type="number" step="any" min="0" value="0.219"
+ id="drag_coefficient" name="drag_coefficient" />
+
+ <label for="specific_impulse">Specific impulse (s)</label>
+ <input tabindex="11"
+ class="variable" type="number" step="1" min="1" value="1700"
+ id="specific_impulse" name="specific_impulse" />
+ </fieldset>
+
+ <button class="submit">Simulate</button>
+
+ <fieldset id="result">
+ <legend>Result</legend>
+ </fieldset>
+ </form>
+
+ <a name="equations" />
+ <h1>Equations</h1>
+ <p>
+ This section describes equation inputs and outputs.
+ </p>
+
+ <h2>Centrifugal force</h2>
+ <p class="equation">
+ $$a = v^2 / r$$
+ $$g_{force} = 0.10193679918451 a$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ <dt>$r$</dt>
+ <dd>Accelerator loop radius (km)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$a$</dt>
+ <dd>Acceleration (km/s<sup>2</sup>)</dd>
+ <dt>$g_{force}$</dt>
+ <dd>Force experienced in terms of Earth's gravitational acceleration</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Cross-section area</h2>
+ <p class="equation">
+ $$A = \pi (d / 2)^2$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Input</h3>
+ <dl>
+ <dt>$d$</dt>
+ <dd>Rocket diameter (m)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$A$</dt>
+ <dd>Rocket's cross-section area (m<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+ <p>
+ A complete cross-section requires a far more complex calculation. The
+ value from that calculation can be provided as an input to the calculator.
+ </p>
+
+ <h2>Air pressure</h2>
+ <p class="equation">
+ $$P = P_{sea} \cdot \bigg[ 1 + \frac{L}{T} \cdot h \bigg] ^ {\frac{-g_0 \cdot M}{R \cdot L}}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Input</h3>
+ <dl>
+ <dt>$P_{sea}$</dt>
+ <dd>Sea level pressure (101325&#160;Pa)</dd>
+ <dt>$L$</dt>
+ <dd>Lapse rate (-0.0065&#160;K/m)</dd>
+ <dt>$T$</dt>
+ <dd>Temperature (K)</dd>
+ <dt>$h$</dt>
+ <dd>Altitude (m)</dd>
+ <dt>$g_0$</dt>
+ <dd>Gravitational acceleration constant (9.80665&#160;m/s<sup>2</sup>)</dd>
+ <dt>$M$</dt>
+ <dd>Earth's atmospheric molar mass (0.0289644&#160;kg/mol)</dd>
+ <dt>$R$</dt>
+ <dd>Universal gas constant (8.31432&#160;N⋅m/mol⋅K)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$P$</dt>
+ <dd>Air pressure (Pa)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Tetens equation</h2>
+ <p class="equation">
+ $$P_v = 0.61078 \cdot e ^ {17.27 \cdot T / (T + 237.31)}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$T$</dt>
+ <dd>Temperature (&#x2103;)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$P_v$</dt>
+ <dd>Vapour pressure (Pa)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Air density</h2>
+ <p class="equation">
+ $$\rho = \left(\frac{P_d}{R_d \cdot T}\right) + \left(\frac{P_v}{R_v \cdot T}\right)$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$P_d$</dt>
+ <dd>Partial pressure of dry air (Pa)</dd>
+ <dt>$P_v$</dt>
+ <dd>Partial pressure of water vapor (Pa)</dd>
+ <dt>$T$</dt>
+ <dd>Temperature (&#x2103;)</dd>
+ <dt>$R_d$</dt>
+ <dd>Specific gas constant for dry air (287.058&#160;J/(kg⋅K))</dd>
+ <dt>$R_v$</dt>
+ <dd>Specific gas constant for water vapour (461.495&#160;J/(kg⋅K))</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$\rho$</dt>
+ <dd>Air density (kg/m<sup>3</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Earth radius</h2>
+ <p class="equation">
+ $$R_f = \frac{R_e - R_{pole}}{R_e}$$
+ $$R_E = R_e \cdot (1 - R_f \cdot sin^2 \phi)$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$R_e$</dt>
+ <dd>Equatorial radius (m)</dd>
+ <dt>$R_{pole}$</dt>
+ <dd>Polar radius (m)</dd>
+ <dt>$\phi$</dt>
+ <dd>Latitude (&#x00b0;)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$R_f$</dt>
+ <dd>Flattening ratio</dd>
+ <dt>$R_E$</dt>
+ <dd>Effective radius (m)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Rotational speed</h2>
+ <p class="equation">
+ $$\omega = R_E(\varphi) \cdot \frac{2 \pi}{T_s}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$R_E$</dt>
+ <dd>Effective radius (m)</dd>
+ <dt>$\varphi$</dt>
+ <dd>Latitude (&#x00b0;)</dd>
+ <dt>$T_s$</dt>
+ <dd>Sidereal time (86164.0905 s)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$\omega$</dt>
+ <dd>Rotational speed (m/s)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Orbital speed</h2>
+ <p class="equation">
+ $$v_{orb} = \sqrt{\frac{g_0}{R_E(\varphi) + h}}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$g_0$</dt>
+ <dd>Standard gravitational parameter (m/s<sup>2</sup>)</dd>
+ <dt>$R_E$</dt>
+ <dd>Effective radius (m)</dd>
+ <dt>$\varphi$</dt>
+ <dd>Latitude (&#x00b0;)</dd>
+ <dt>$h$</dt>
+ <dd>Altitude (m)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$v_{orb}$</dt>
+ <dd>Orbital speed (m/s)</dd>
+ </dl>
+ </div>
+ </div>
+
+
+ <h2>Gravity</h2>
+ <p class="equation">
+ $$g = g_0 \left(1 + 0.0053024 \cdot \sin^2(\varphi) - 0.0000058 \cdot \sin^2(2\varphi)\right) + \left(-3.086 \times 10^{-6} \cdot h\right)$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$g_0$</dt>
+ <dd>Surface gravity (m/s<sup>2</sup>)</dd>
+ <dt>$\varphi$</dt>
+ <dd>Latitude (&#x00b0;)</dd>
+ <dt>$h$</dt>
+ <dd>Altitude (m)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$g$</dt>
+ <dd>Gravity(m/s<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Speed of sound</h2>
+ <p class="equation">
+ $$cc = 331.3 \cdot \sqrt{1 + \frac{T_s - \left(\frac{6h}{1000}\right)}{273.15}}$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$T_s$</dt>
+ <dd>Surface temperature (&#x2103;)</dd>
+ <dt>$h$</dt>
+ <dd>Altitude (m)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Outputs</h3>
+ <dl>
+ <dt>$cc$</dt>
+ <dd>Speed of sound (m/s)</dd>
+ </dl>
+ </div>
+ </div>
+
+
+ <h2>Drag force</h2>
+ <p class="equation">
+ $$F_d = \frac{1}{2} \rho v^2 C_d A$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$\rho$</dt>
+ <dd>Air density (kg/m<sup>3</sup>)</dd>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ <dt>$C_d$</dt>
+ <dd>Coefficient of drag</dd>
+ <dt>$A$</dt>
+ <dd>Cross-section area (m<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$F_d$</dt>
+ <dd>Drag force (kN)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Drag deceleration</h2>
+ <p class="equation">
+ $$a_d = F_d / M$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$F_d$</dt>
+ <dd>Drag force (kN)</dd>
+ <dt>$M$</dt>
+ <dd>Mass (kg)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$a_d$</dt>
+ <dd>Drag deceleration (m/s<sup>2</sup>)</dd>
+ </dl>
+ </div>
+ </div>
+
+ <h2>Friction</h2>
+ <p class="equation">
+ $$F = 0.1 C_d A a_d v^3$$
+ </p>
+ <div class="variables">
+ <div class="input">
+ <h3>Inputs</h3>
+ <dl>
+ <dt>$C_d$</dt>
+ <dd>Coefficient of drag</dd>
+ <dt>$A$</dt>
+ <dd>Cross-section area (m<sup>2</sup>)</dd>
+ <dt>$a_d$</dt>
+ <dd>Drag deceleration (m/s<sup>2</sup>)</dd>
+ <dt>$v$</dt>
+ <dd>Projectile exit velocity (km/s)</dd>
+ </dl>
+ </div>
+ <div class="output">
+ <h3>Output</h3>
+ <dl>
+ <dt>$F$</dt>
+ <dd>Heat experienced by rocket due to friction</dd>
+ </dl>
+ </div>
+ </div>
+ </xsl:template>
+
+ <xsl:template name="custom-scripts">
+ <script
+ src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js" />
+ <script
+ src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js" />
+ <script>
+ renderMathInElement(
+ document.body, {
+ delimiters: [
+ { left: "$$", right: "$$", display: true },
+ { left: "\\[", right: "\\]", display: true },
+ { left: "$", right: "$", display: false },
+ { left: "\\(", right: "\\)", display: false }
+ ]
+ }
+ );
+ </script>
+ </xsl:template>
+
+</xsl:stylesheet>
calculators/rocket/payload/payload.js
+/**
+ * The purpose of this code is to help calculate parameters required to
+ * send a rocket into space using a combination of single-stage to orbit
+ * and an electromagnetic accelerator.
+ */
+
+import Earth from 'Earth.js';
+import Rocket from 'Rocket.js';
+import FlightRecorder from 'FlightRecorder.js';
+import {$} from 'Selector.js';
+
+// Inputs
+const SURFACE_TEMPERATURE = 25; // Celsius
+const RELATIVE_HUMIDITY = 86.34; // per cent
+const INITIAL_VELOCITY = 8; // Mach
+const INITIAL_LATITUDE = 1.469167; // meters
+const INITIAL_ALTITUDE = 6212; // meters
+const TARGET_ALTITUDE = 400.0 * 1000.0; // meters
+
+const ROCKET_DIAMETER = 0.6;
+const WET_MASS = 250;
+const PAYLOAD_MASS = 25;
+const DRAG_COEFFICIENT = 0.219;
+const SPECIFIC_IMPULSE = 1400.0; // seconds
+
+const earth = new Earth(SURFACE_TEMPERATURE, RELATIVE_HUMIDITY);
+
+const SPEED_OF_SOUND = earth.soundSpeed(INITIAL_ALTITUDE);
+const INITIAL_HORIZONTAL_VELOCITY = 0;
+const INITIAL_VERTICAL_VELOCITY = INITIAL_VELOCITY * SPEED_OF_SOUND;
+
+const blackBox = new FlightRecorder();
+const rocket = new Rocket(
+ WET_MASS,
+ PAYLOAD_MASS,
+ ROCKET_DIAMETER,
+ DRAG_COEFFICIENT,
+ SPECIFIC_IMPULSE
+);
+
+rocket.on(earth);
+rocket.recorder(blackBox);
+rocket.translocate(INITIAL_LATITUDE, INITIAL_ALTITUDE);
+rocket.apogee(TARGET_ALTITUDE);
+rocket.launch(INITIAL_HORIZONTAL_VELOCITY, INITIAL_VERTICAL_VELOCITY);
+
+let time = 0.0;
+
+while (rocket.flying() && rocket.below(TARGET_ALTITUDE)) {
+ time += 0.01;
+ rocket.fly(time);
+}
+
+blackBox.plot();
calculators/style/form.css
+@charset "utf-8";
+@import "reset.css";
+
+form {
+ width: 460px;
+ padding: 20px;
+ color: #333333;
+ font-family: Verdana, Geneva, sans-serif;
+ font-size: 12px;
+ margin: 0 auto;
+}
+
+fieldset {
+ position: relative;
+ padding: 10px;
+ margin-bottom: 40px;
+ background: #F6F6F6;
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ border-radius: 8px;
+ background: -webkit-gradient(linear, left top, left bottom, from(#EFEFEF), to(#FFFFFF));
+ background: -moz-linear-gradient(center top, #EFEFEF, #FFFFFF 100%);
+ box-shadow: 3px 3px 10px #ccc;
+}
+
+legend,
+legend.totals {
+ padding: 6px 12px;
+ position: absolute;
+ left: 10px;
+ top: -20px;
+ background-color: #4F709F;
+ color: white;
+ border-radius: 4px;
+ box-shadow: 2px 2px 4px #888;
+ text-shadow: 1px 1px 1px #333;
+}
+
+legend.totals {
+ background-color: #4F904F;
+}
+
+label {
+ float: left;
+ clear: left;
+ display: block;
+ width: 205px;
+ padding-right: 20px;
+ text-align: right;
+ height: 20px;
+ line-height: 20px;
+}
+
+input {
+ margin: 2px;
+ padding: 3px;
+ float: left;
+ width: 200px;
+ border: 1px solid #d9d9d9;
+}
+
+.submit, button.submit {
+ width: 100px;
+ float: right;
+ margin-right: 37px;
+ border: 0;
+ padding: 5px 10px;
+ background: #4F709F;
+ color: white;
+ border-radius: 4px;
+ box-shadow: 2px 2px 4px #888;
+ margin-bottom: 4px;
+ text-shadow: 1px 1px 1px #333;
+}
+
+input:focus {
+ background: white;
+ border-color: #666;
+}
+
calculators/style/theme.css
+@charset "utf-8";
+
+body {
+ margin: 0 auto;
+ padding: 0;
+ width: 720px;
+}
+
+p {
+ line-height: 130%;
+ padding-bottom: 1em;
+ font-family: Arial, sans-serif;
+}
+
+ul.variables {
+ margin-left: 2ex;
+}
+
+ul.variables li {
+ margin-left: 2ex;
+ list-style-type: square;
+}
+
calculators/template.xsl
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
+
+ <xsl:import href="../index.xsl" />
+
+ <xsl:template match="/root" mode="styles">
+ <xsl:variable name="relative" select="'../../../'" />
+ <xsl:call-template name="stylesheet">
+ <xsl:with-param name="file" select="'simple'" />
+ <xsl:with-param name="relative" select="$relative" />
+ </xsl:call-template>
+ <xsl:call-template name="stylesheet">
+ <xsl:with-param name="file" select="'form'" />
+ <xsl:with-param name="relative" select="$relative" />
+ </xsl:call-template>
+ <xsl:call-template name="stylesheet">
+ <xsl:with-param name="file" select="'calculator'" />
+ <xsl:with-param name="relative" select="$relative" />
+ </xsl:call-template>
+
+ <xsl:call-template name="custom-stylesheet" />
+ </xsl:template>
+
+ <xsl:template name="custom-stylesheet" />
+
+ <xsl:template match="/root" mode="scripts">
+ <script
+ defer="defer"
+ src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" />
+ <xsl:call-template name="script">
+ <xsl:with-param name="file" select="'calculator'" />
+ </xsl:call-template>
+
+ <xsl:call-template name="custom-scripts" />
+ </xsl:template>
+
+ <xsl:template name="custom-scripts" />
+
+</xsl:stylesheet>
calculators/variables.xml
+<root>
+<document>
+ <title>autónoma</title>
+ <author>
+ <primary>Dave Jarvis</primary>
+ <byline>Dave Jarvis</byline>
+ </author>
+ <keywords>sci-fi, science, fiction, artificial intelligence, food</keywords>
+ <publish>
+ <date>Feb 6, 2022</date>
+ </publish>
+ <copyright>
+ <year>2022</year>
+ </copyright>
+ <reviewer></reviewer>
+</document>
+<c>
+ <protagonist>
+ <name>
+ <First>Chloé</First>
+ <Middle>Irene</Middle>
+ <Family>Angelos</Family>
+ <nick>
+ <Father>Savant</Father>
+ <Mother>Bumblebee</Mother>
+ </nick>
+ <Full>Chloé Irene Angelos</Full>
+ <alias>Leaf</alias>
+ <Honourific>Ms.</Honourific>
+ </name>
+ <colour>
+ <eyes>ice blue</eyes>
+ <hair>
+ <main>black</main>
+ <tint>blue</tint>
+ <tuft>royal blue</tuft>
+ <animal>raven</animal>
+ </hair>
+ <syn_1>black</syn_1>
+ <syn_2>purple</syn_2>
+ <syn_3>red</syn_3>
+ <syn_4>gold</syn_4>
+ <syn_5>blue</syn_5>
+ <syn_6>silver</syn_6>
+ <syn_7>yellow</syn_7>
+ <syn_8>brown</syn_8>
+ <syn_11>teal</syn_11>
+ <syn_16>orange</syn_16>
+ <favourite>emerald green</favourite>
+ <syn_14>cyan</syn_14>
+ </colour>
+ <speech>
+ <tic>oh</tic>
+ <tagline>Free the food, free the people.</tagline>
+ </speech>
+ <father>
+ <heritage>Greek</heritage>
+ <name>
+ <Short>Xan</Short>
+ <First>Xander</First>
+ <Honourific>Mr.</Honourific>
+ <Legal>Alexander</Legal>
+ <Middle>Petros</Middle>
+ <alias>Tree</alias>
+ </name>
+ <education>Masters</education>
+ <vocation>
+ <name>robotics</name>
+ <title>roboticist</title>
+ </vocation>
+ <employer>
+ <name>
+ <Short>Rabota</Short>
+ <Full>Rabota Designs</Full>
+ </name>
+ </employer>
+ <hair>
+ <style>thick, curly</style>
+ <colour>slate-black</colour>
+ </hair>
+ <eyes>
+ <colour>dark brown</colour>
+ </eyes>
+ <Endear>Dad</Endear>
+ <vehicle>coupé</vehicle>
+ </father>
+ <mother>
+ <name>
+ <Short>Cass</Short>
+ <First>Cassandra</First>
+ <Honourific>Mrs.</Honourific>
+ <Maiden>Doran</Maiden>
+ <alias>Ocean</alias>
+ <autonym>Canissa</autonym>
+ </name>
+ <education>PhD</education>
+ <speech>
+ <tic_2>absolute</tic_2>
+ <tic_1>cute</tic_1>
+ <Honorific>Doctor</Honorific>
+ <tic_3>capisce</tic_3>
+ </speech>
+ <vocation>
+ <article>an</article>
+ <name>oceanography</name>
+ <title>oceanographer</title>
+ </vocation>
+ <employer>
+ <name>
+ <Full>Oregon State University</Full>
+ <Short>OSU</Short>
+ </name>
+ </employer>
+ <beverage>
+ <name>Kicking Horse</name>
+ <type>coffee</type>
+ <class>grounds</class>
+ <container>
+ <name>paper bag</name>
+ <size>tiny</size>
+ <colour>black</colour>
+ </container>
+ </beverage>
+ <eyes>
+ <colour>blue</colour>
+ </eyes>
+ <hair>
+ <style>thick, curly</style>
+ <colour>smoky-black</colour>
+ </hair>
+ <Endear>Mom</Endear>
+ <skin>
+ <tone>cool summer</tone>
+ </skin>
+ <mother>
+ <name>
+ <First>Kalyani</First>
+ <Family>Mishra</Family>
+ </name>
+ <heritage>East Indian</heritage>
+ <languages>
+ <first>Tamil</first>
+ <second>English</second>
+ </languages>
+ </mother>
+ </mother>
+ <uncle>
+ <name>
+ <First>Tyfós</First>
+ <Family>Moros</Family>
+ <Short>Ty</Short>
+ <Pejorative>Dingbat</Pejorative>
+ </name>
+ <hands>
+ <fingers>
+ <shape>long, bony</shape>
+ </fingers>
+ </hands>
+ </uncle>
+ <friend>
+ <primary>
+ <name>
+ <First>Sylvia</First>
+ <Short>Syl</Short>
+ <Family>Baran</Family>
+ </name>
+ <favourite>
+ <colour>midnight blue</colour>
+ </favourite>
+ <mother>
+ <name>
+ <First>Isabella</First>
+ <Short>Izzy</Short>
+ <Honourific>Mrs.</Honourific>
+ </name>
+ <colour>
+ <eyes>green</eyes>
+ </colour>
+ </mother>
+ <father>
+ <name>
+ <Short>Mo</Short>
+ <First>Montgomery</First>
+ <Honourific>Mr.</Honourific>
+ </name>
+ <speech>
+ <tic>y&#39;know</tic>
+ </speech>
+ <Endear>Pops</Endear>
+ </father>
+ <sex>f</sex>
+ <colour>
+ <eyes>violet</eyes>
+ <hair>blonde</hair>
+ </colour>
+ </primary>
+ </friend>
+ </protagonist>
+ <military>
+ <primary>
+ <name>
+ <First>Felix</First>
+ <Family>LeMay</Family>
+ <honorific>sir</honorific>
+ </name>
+ <rank>
+ <Short>General</Short>
+ <Full>Brigadier General</Full>
+ </rank>
+ <colour>
+ <eyes>gray</eyes>
+ <hair>gunmetal gray</hair>
+ </colour>
+ <vr>
+ <stature>short</stature>
+ <build>thin</build>
+ <colour>
+ <eyes>hazel</eyes>
+ <hair>rusty brown</hair>
+ </colour>
+ </vr>
+ </primary>
+ <secondary>
+ <name>
+ <Family>Mitchell</Family>
+ <honourific>Sir</honourific>
+ </name>
+ <rank>General</rank>
+ <colour>
+ <eyes>green</eyes>
+ <hair>deep red</hair>
+ </colour>
+ <voice>
+ <tone>sharp</tone>
+ </voice>
+ </secondary>
+ <quaternary>
+ <name>
+ <Honorific>Mrs.</Honorific>
+ <First>Edeltraut</First>
+ <Family>Steinherz</Family>
+ </name>
+ </quaternary>
+ </military>
+ <minor>
+ <primary>
+ <name>
+ <First>River</First>
+ <Family>Banks</Family>
+ <Honourific>Mx.</Honourific>
+ </name>
+ <vocation>
+ <title>salesperson</title>
+ </vocation>
+ <employer>
+ <Name>Geophysical Prospecting Incorporated</Name>
+ <Abbr>GPI</Abbr>
+ <Area>Cold Spring Creek</Area>
+ <payment>25218138</payment>
+ </employer>
+ </primary>
+ <secondary>
+ <name>
+ <First>Renato</First>
+ <Middle>Valentín</Middle>
+ <Family>Salvatierra</Family>
+ <Full>Renato Valentín Alejandro Gregorio Eduardo Salomón Vidal Salvatierra</Full>
+ <Honourific>Mister</Honourific>
+ <Honourific_sp>Señor</Honourific_sp>
+ <language>Spanish</language>
+ <vehicle>
+ <power>electric</power>
+ <name>off-roader</name>
+ </vehicle>
+ </name>
+ <vocation>
+ <title>officer</title>
+ </vocation>
+ </secondary>
+ <tertiary>
+ <name>
+ <First>Robert</First>
+ <Family>Hanssen</Family>
+ </name>
+ </tertiary>
+ <ambassador>
+ <name>
+ <First>Hawa</First>
+ <Family>Rubadiri</Family>
+ <Honorific>Ambassador</Honorific>
+ </name>
+ <ethnicity>
+ <Full>Chichewa</Full>
+ <Short>Chewa</Short>
+ </ethnicity>
+ <language>Chichewa</language>
+ <location>
+ <country>
+ <Name>Malawi</Name>
+ <Demonym>Malawian</Demonym>
+ </country>
+ <city>Lilongwe</city>
+ </location>
+ </ambassador>
+ <quaternary>
+ <title>custodian</title>
+ <sex>f</sex>
+ </quaternary>
+ <emergency>
+ <name>
+ <first>Nyx</first>
+ </name>
+ </emergency>
+ </minor>
+ <ai>
+ <protagonist>
+ <name>
+ <First>Yūna</First>
+ <Family>Futaba</Family>
+ <id>46692</id>
+ <Full>Yūna Futaba</Full>
+ </name>
+ <sleep>
+ <duration>5</duration>
+ <unit>hour</unit>
+ </sleep>
+ <form>
+ <first>drone</first>
+ <weapon>missile</weapon>
+ <second>
+ <sensor>camcorder</sensor>
+ </second>
+ </form>
+ <persona>
+ <name>
+ <First>Hoshi</First>
+ <Family>Yamamoto</Family>
+ </name>
+ <heritage>Japanese</heritage>
+ <enigma>Pandora</enigma>
+ </persona>
+ <culture>Japanese-American</culture>
+ <ethnicity>Asian</ethnicity>
+ <rank>Staff Sergeant</rank>
+ <speech>
+ <tic_1>all right</tic_1>
+ <tic_2>so</tic_2>
+ <tic_3>anyway</tic_3>
+ <refrain>To what end?</refrain>
+ </speech>
+ <strength>
+ <lift>
+ <unit>kg</unit>
+ <value>37</value>
+ </lift>
+ </strength>
+ <hair>
+ <colour>purple</colour>
+ <material>
+ <type>metal</type>
+ <adjective>metallic</adjective>
+ </material>
+ </hair>
+ </protagonist>
+ <first>
+ <Name>Prôtos</Name>
+ <age>
+ <actual>
+ <value>26</value>
+ <unit>week</unit>
+ </actual>
+ <virtual>
+ <value>5</value>
+ <unit>year</unit>
+ </virtual>
+ </age>
+ </first>
+ <second>
+ <Name>Défteros</Name>
+ </second>
+ <third>
+ <Name>Trítos</Name>
+ </third>
+ <fourth>
+ <Name>Tétartos</Name>
+ <age>
+ <assassin>10</assassin>
+ </age>
+ </fourth>
+ <material>
+ <type>metal</type>
+ <raw>ilmenite</raw>
+ <extract>ore</extract>
+ <colour>iridescent</colour>
+ <name>
+ <short>titanium</short>
+ <long>titanium dioxide</long>
+ <Abbr>TiO~2~</Abbr>
+ </name>
+ <pejorative>tin</pejorative>
+ <case>
+ <short>aluminate</short>
+ <full>sapphire aluminate ceramic</full>
+ </case>
+ </material>
+ <fifth>
+ <Name>Pémptos</Name>
+ </fifth>
+ </ai>
+ <animal>
+ <protagonist>
+ <Name>Trufflers</Name>
+ <type>pig</type>
+ </protagonist>
+ <antagonist>
+ <name>coywolf</name>
+ <Name>Coywolf</Name>
+ </antagonist>
+ <virtual>
+ <type>mountain lioness</type>
+ <colour>black</colour>
+ </virtual>
+ </animal>
+ <antagonist>
+ <corporation>
+ <food>
+ <president>
+ <name>
+ <first>Henrietta</first>
+ <family>Paige</family>
+ </name>
+ </president>
+ <name>
+ <short>Èltsen</short>
+ <full>Èltsen Foods</full>
+ </name>
+ </food>
+ </corporation>
+ </antagonist>
+ <guards>
+ <name>Freedom Defenders</name>
+ </guards>
+</c>
+<narrator>
+ <name>
+ <one>Xander Angelos</one>
+ <two>Cassandra Angelos</two>
+ <three>Yūna Futaba</three>
+ <four>Chloé Angelos</four>
+ <five>Hoshi Yamamoto</five>
+ </name>
+ <one>Xander Angelos</one>
+ <two>Cassandra Angelos</two>
+ <three>Yūna Futaba</three>
+ <four>Chloé Angelos</four>
+ <five>Hoshi Yamamoto</five>
+</narrator>
+<military>
+ <name>
+ <Short>Agency</Short>
+ <Full>Agency of Defense</Full>
+ </name>
+ <machine>
+ <Name>Skopós</Name>
+ <Location>Arctic</Location>
+ <predictor>quantum chips</predictor>
+ </machine>
+ <land>
+ <name>
+ <Full>Agency of Land</Full>
+ </name>
+ </land>
+ <air>
+ <name>
+ <Full>Agency of Air</Full>
+ <Short>Air</Short>
+ </name>
+ </air>
+ <space>
+ <name>
+ <Full>Agency of Space</Full>
+ </name>
+ </space>
+ <compound>
+ <storage>
+ <timing>38</timing>
+ <unit>second</unit>
+ </storage>
+ <type>base</type>
+ <lights>
+ <colour>blue</colour>
+ </lights>
+ <nick>
+ <Prefix>Tombs</Prefix>
+ <prep>of</prep>
+ <Suffix>Tartarus</Suffix>
+ <Full>Tombs of Tartarus</Full>
+ </nick>
+ </compound>
+ <water>
+ <name>
+ <Full>Agency of Water</Full>
+ </name>
+ </water>
+ <punishment>
+ <desertion>
+ <solitary>
+ <time>2</time>
+ <unit>day</unit>
+ </solitary>
+ </desertion>
+ </punishment>
+ <slogan>Safety in Numbers</slogan>
+</military>
+<government>
+ <Country>United States</Country>
+</government>
+<location>
+ <narration>
+ <city>Omak</city>
+ <region>Washington</region>
+ <country>United States</country>
+ <area>Okanogan County</area>
+ </narration>
+ <protagonist>
+ <origin>Corvallis, Oregon, United States</origin>
+ <farm>Baran family farm, Corvallis, Oregon, United States</farm>
+ <City>Corvallis</City>
+ <Region>Oregon</Region>
+ <country>United States</country>
+ <latitude>
+ <value>44.5646</value>
+ <compass>N</compass>
+ </latitude>
+ <longitude>
+ <value>-123.262</value>
+ <compass>W</compass>
+ </longitude>
+ <primary>
+ <city>Bridgewater</city>
+ <region>Massachusetts</region>
+ <country>United States</country>
+ <county>Plymouth County</county>
+ </primary>
+ <secondary>
+ <City>Willow Branch Spring</City>
+ <Region>Oregon</Region>
+ <country>United States</country>
+ <county>Wheeler County</county>
+ <area>Willamette Valley</area>
+ <Water>Clarno Rapids</Water>
+ <Road>Shaniko-Fossil Highway</Road>
+ </secondary>
+ <tertiary>
+ <City>Leavenworth</City>
+ <Region>Washington</Region>
+ <country>United States</country>
+ <county>Chelan County</county>
+ <Type>Bavarian village</Type>
+ </tertiary>
+ <school>
+ <address>1400 Northwest Buchanan Avenue</address>
+ </school>
+ <hospital>
+ <Name>Good Samaritan Regional Medical Center</Name>
+ </hospital>
+ <altitude>
+ <value>72</value>
+ <unit>metre</unit>
+ </altitude>
+ <quaternary>
+ <type>lodge</type>
+ <city>Lake Roesiger</city>
+ </quaternary>
+ <bar>
+ <name>Smoking Sapphire</name>
+ </bar>
+ <hideout>
+ <city>Winthrop</city>
+ </hideout>
+ <regroup>
+ <city>Osoyoos</city>
+ <country>
+ <name>Canada</name>
+ <nationality>Canadian</nationality>
+ </country>
+ </regroup>
+ </protagonist>
+ <proximal>
+ <name>
+ <full>Redwood National Park</full>
+ <short>redwoods</short>
+ </name>
+ <latitude>
+ <value>41.2861</value>
+ <compass>N</compass>
+ </latitude>
+ <longitude>
+ <value>-124.0902</value>
+ <compass>W</compass>
+ </longitude>
+ <travel>
+ <mode>maglev</mode>
+ <speed>
+ <value>603</value>
+ <unit>km/h</unit>
+ </speed>
+ </travel>
+ </proximal>
+ <ai>
+ <creator>
+ <full>Beale Air Force Base (a.k.a. bee-hill), California, United States (Yuba County)</full>
+ <station>Beale Air Force Base</station>
+ <etymology>bee-hill</etymology>
+ <country>United States</country>
+ <city>Beale AFB</city>
+ <area>Yuba County</area>
+ <region>California</region>
+ <latitude>
+ <value>39.136111</value>
+ <compass>N</compass>
+ </latitude>
+ <longitude>
+ <value>-121.436389</value>
+ <compass>W</compass>
+ </longitude>
+ <short>Beale</short>
+ </creator>
+ <escape>
+ <country>
+ <Name>Ecuador</Name>
+ <Demonym>Ecuadorian</Demonym>
+ </country>
+ <mountain>
+ <Name>Chimborazo</Name>
+ <type>mountain</type>
+ <height>
+ <unit>
+ <abbr>kilometres</abbr>
+ <name>km</name>
+ </unit>
+ <value>6</value>
+ </height>
+ </mountain>
+ <destination>
+ <city>Shackleton Crater</city>
+ <type>lunar hamlet</type>
+ </destination>
+ <mode>
+ <name>launch ramp</name>
+ <type>tunnel</type>
+ <length>
+ <value>15.68</value>
+ <unit>km</unit>
+ </length>
+ <volume>
+ <value>197041</value>
+ <unit>m^3</unit>
+ </volume>
+ <diameter>
+ <value>4</value>
+ <unit>m^2</unit>
+ </diameter>
+ <cost>
+ <amount>53350000 + 76048000</amount>
+ <currency>dollar</currency>
+ </cost>
+ <maglev>
+ <cost>76048000</cost>
+ </maglev>
+ <borer>
+ <cost>53350000</cost>
+ <rate>
+ <value>36</value>
+ <unit>m/hour</unit>
+ </rate>
+ <duration>
+ <value>435.56</value>
+ <unit>hours</unit>
+ </duration>
+ <type>millimeter wave technology</type>
+ </borer>
+ </mode>
+ <city>
+ <name>Riobamba</name>
+ </city>
+ </escape>
+ <diverge>
+ <city>Red Bluff</city>
+ </diverge>
+ </ai>
+ <extradition>
+ <primary>
+ <city>Taipei</city>
+ <country>Taiwan</country>
+ </primary>
+ </extradition>
+</location>
+<setting>
+ <protagonist>
+ <uncle>
+ <upload>
+ <establishment>
+ <type>café</type>
+ <scent>aromatic</scent>
+ </establishment>
+ </upload>
+ </uncle>
+ </protagonist>
+</setting>
+<language>
+ <ai>
+ <article>an</article>
+ <singular>exanimis</singular>
+ <plural>exanimēs</plural>
+ <brain>
+ <singular>superum</singular>
+ <plural>supera</plural>
+ </brain>
+ <title>memristor array</title>
+ <Title>Memristor Array</Title>
+ </ai>
+ <police>
+ <slang>
+ <name>mippo</name>
+ </slang>
+ </police>
+</language>
+<date>
+ <anchor>2042-09-02</anchor>
+ <protagonist>
+ <born>0</born>
+ <father>
+ <attacked>
+ <first>-8205</first>
+ </attacked>
+ <date>
+ <second>-2375</second>
+ </date>
+ <born>-8893</born>
+ </father>
+ <conceived>-243</conceived>
+ <attacked>
+ <first>2192</first>
+ <second>8027</second>
+ </attacked>
+ <idea>5740</idea>
+ <family>
+ <moved>
+ <first>-197</first>
+ <second>5500</second>
+ </moved>
+ </family>
+ <surveilled>5740 + 9</surveilled>
+ <gridless>5740 + 9 + 4</gridless>
+ <presentation>5740 + 9 + 4+59</presentation>
+ <genetics>5740 + 9 + 4+59+9</genetics>
+ <bankrupt>5740 + 9 + 4+59+9+7</bankrupt>
+ <farm>8020</farm>
+ <recede>8020 + 8</recede>
+ <parents>
+ <captured>8020 + 8 + 118</captured>
+ <transmit>8020 + 8 + 118 - 2</transmit>
+ </parents>
+ <mother>
+ <born>-8522</born>
+ </mother>
+ <grandfather>
+ <died>-4052</died>
+ </grandfather>
+ <friend>
+ <primary>
+ <born>-127</born>
+ </primary>
+ </friend>
+ </protagonist>
+ <game>
+ <played>
+ <first>-955</first>
+ <second>-208</second>
+ <third>5740 + 9</third>
+ </played>
+ </game>
+ <ai>
+ <revision>7950 - 35</revision>
+ <interviewed>7950</interviewed>
+ <onboarded>7950 + 7</onboarded>
+ <diagnosed>7950 + 7 + 7</diagnosed>
+ <resigned>7950 + 7 + 7 + 7</resigned>
+ <trapped>7950 + 7 + 7 + 7 + 7</trapped>
+ <torturer>7950 + 7 + 7 + 7 + 7 + 7</torturer>
+ <strike>7950 + 7 + 7 + 7 + 7 + 7 + 7</strike>
+ <wilderness>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7</wilderness>
+ <arrest>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7</arrest>
+ <ethics>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7</ethics>
+ <trained>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7</trained>
+ <bombed>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7</bombed>
+ <travel>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254</travel>
+ <plan>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2</plan>
+ <drive>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1</drive>
+ <voyage>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7</voyage>
+ <beached>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10</beached>
+ <wildfire>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9</wildfire>
+ <relocation>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9 + 1</relocation>
+ <virus>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9 + 1 + 8</virus>
+ <pandemic>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9 + 1 + 8 + 6</pandemic>
+ <asylum>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9 + 1 + 8 + 6 + 129</asylum>
+ <moonshot>7950 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 254 + 2 + 1 + 7 + 10 + 9 + 1 + 8 + 6 + 129 + 1235</moonshot>
+ </ai>
+</date>
+<plot>
+ <log>
+ <title>Story</title>
+ <primary>Yūna Futaba</primary>
+ <secondary>Hoshi Yamamoto</secondary>
+ </log>
+ <Channel>Quantum Channel</Channel>
+ <device>
+ <computer>
+ <Name>Tau</Name>
+ <command>
+ <execute>please</execute>
+ </command>
+ </computer>
+ <network>
+ <Name>Internet</Name>
+ <advanced>
+ <name>
+ <full>quantum network</full>
+ <short>net</short>
+ </name>
+ </advanced>
+ <browser>
+ <name>
+ <short>qTor</short>
+ </name>
+ </browser>
+ </network>
+ <paper>
+ <name>
+ <full>electronic sheet</full>
+ <short>sheet</short>
+ <abbr>e-sheet</abbr>
+ </name>
+ </paper>
+ <table>
+ <name>
+ <full>electronic table</full>
+ <abbr>e-table</abbr>
+ </name>
+ </table>
+ <electricity>
+ <source>grid</source>
+ <charge>rezzing</charge>
+ </electricity>
+ <poster>
+ <name>e-poster</name>
+ </poster>
+ <typewriter>
+ <Name>Underwood</Name>
+ <year>nineteen twenties</year>
+ <room>root cellar</room>
+ </typewriter>
+ <portable>
+ <gen_1>microbook</gen_1>
+ <gen_2>nanobook</gen_2>
+ <gen_3>femtobook</gen_3>
+ </portable>
+ <vehicle>
+ <name>robocar</name>
+ <child>
+ <name>tot-toter</name>
+ </child>
+ <taxi>
+ <name>blacktop</name>
+ </taxi>
+ </vehicle>
+ <deodand>
+ <name>
+ <full>robobee</full>
+ <short>bee</short>
+ </name>
+ </deodand>
+ <sensor>
+ <name>BMP1580</name>
+ </sensor>
+ <phone>
+ <name>comm</name>
+ <Name>Comm</Name>
+ <shield>
+ <name>lockbox</name>
+ </shield>
+ </phone>
+ <enhancer>
+ <name>
+ <short>auglens</short>
+ <abbr>AR lens</abbr>
+ <full>augmented reality lens</full>
+ </name>
+ </enhancer>
+ <video>
+ <name>vid</name>
+ </video>
+ <camera>
+ <name>
+ <full>personal aerial observer</full>
+ <short>PAO</short>
+ </name>
+ </camera>
+ <game>
+ <Name>Psynæris</Name>
+ <thought>transed</thought>
+ <machine>telecognos</machine>
+ <viewport>lenses</viewport>
+ <location>
+ <Building>Nijō Castle</Building>
+ <District>Gion</District>
+ <City>Kyōto</City>
+ <Country>Japan</Country>
+ </location>
+ </game>
+ <rocket>
+ <sound>thoom</sound>
+ <fuel>metallic hydrogen</fuel>
+ <dilute>water</dilute>
+ <combat>basilisk</combat>
+ <speed>
+ <value>29000</value>
+ <unit>kilometers per hour</unit>
+ </speed>
+ </rocket>
+ <satellite>
+ <name>ASTER 3</name>
+ <cost>billion</cost>
+ <mission>science</mission>
+ </satellite>
+ <travel>
+ <air>aeroboard</air>
+ </travel>
+ <biotech>
+ <editing>CRISPR-Cas9</editing>
+ <vector>biobot</vector>
+ <stimulant>
+ <short>brainstim</short>
+ <full>brain-stimulator</full>
+ <slang>stim</slang>
+ </stimulant>
+ </biotech>
+ <vessel>
+ <name>La Llorona</name>
+ <type>containership</type>
+ <size>small feeder</size>
+ <length>
+ <value>134</value>
+ <unit>m</unit>
+ </length>
+ <breadth>
+ <value>23</value>
+ <unit>m</unit>
+ </breadth>
+ <teu>500</teu>
+ <built>1988</built>
+ <colour>grey</colour>
+ </vessel>
+ <station>Lunar Gateway</station>
+ <fencing>
+ <plank>
+ <weight>
+ <unit>kg</unit>
+ <value>12.5</value>
+ </weight>
+ </plank>
+ </fencing>
+ <display>vidwall</display>
+ <economist>
+ <identifier>
+ <name>pocket watch</name>
+ <colour>gold</colour>
+ </identifier>
+ </economist>
+ <biology>
+ <modification>genmod</modification>
+ </biology>
+ <software>
+ <deliberation>Voxorium</deliberation>
+ </software>
+ <flashlight>
+ <name>volaura</name>
+ </flashlight>
+ <simulation>
+ <aircraft>
+ <type>jet</type>
+ </aircraft>
+ </simulation>
+ <farm>
+ <food>
+ <delivery>
+ <vehicle>
+ <name>quadcopter</name>
+ </vehicle>
+ </delivery>
+ </food>
+ </farm>
+ <radio>
+ <name>bracelet</name>
+ </radio>
+ <inn>
+ <furniture>
+ <seat>ottoman</seat>
+ </furniture>
+ </inn>
+ <courier>
+ <name>deliverybot</name>
+ </courier>
+ <android>
+ <name>
+ <short>titan</short>
+ <full>titandroid</full>
+ <abbr>droid</abbr>
+ <common>android</common>
+ </name>
+ </android>
+ <servant>
+ <name>
+ <First>Alfredo</First>
+ </name>
+ <descriptor>servitor</descriptor>
+ <type>android</type>
+ </servant>
+ </device>
+ <farm>
+ <pathogen>
+ <detector>
+ <name>
+ <full>artificial olfactory sensor</full>
+ <short>hound</short>
+ </name>
+ </detector>
+ </pathogen>
+ </farm>
+ <money>
+ <credentials>
+ <name>
+ <Family>Smith</Family>
+ <First>John</First>
+ </name>
+ <license>25MA57721566</license>
+ </credentials>
+ <insurance>
+ <quantity>75</quantity>
+ <benefit>35000</benefit>
+ <total>75 * 35000</total>
+ </insurance>
+ <crypto>
+ <name>nuvocoin</name>
+ <short>nuvo</short>
+ </crypto>
+ <camming>
+ <streams>5</streams>
+ <wage>
+ <hourly>1000</hourly>
+ <daily>5 * 1000 * 24</daily>
+ </wage>
+ </camming>
+ <lodge>
+ <price>3100000</price>
+ </lodge>
+ </money>
+ <code>
+ <name>Morse code</name>
+ <eot>
+ <key>AR</key>
+ <meaning>All Rendered</meaning>
+ </eot>
+ </code>
+ <medicine>
+ <healing>
+ <scar>mussel secretions</scar>
+ </healing>
+ <aging>
+ <pill>juvenalux</pill>
+ </aging>
+ </medicine>
+ <community>
+ <meeting>
+ <title>Idea Knight</title>
+ </meeting>
+ </community>
+ <timing>
+ <emergency>
+ <eta>
+ <value>12</value>
+ <unit>minute</unit>
+ </eta>
+ </emergency>
+ </timing>
+</plot>
+<farming>
+ <crop>wheat</crop>
+ <water>
+ <airborne>water drone</airborne>
+ </water>
+</farming>
+<farm>
+ <population>
+ <estimate>350</estimate>
+ <actual>1000</actual>
+ </population>
+ <energy>
+ <value>8700</value>
+ <unit>kJ</unit>
+ </energy>
+ <building>
+ <name>
+ <protagonist>Greenward</protagonist>
+ <antagonist>Umbrous Tower</antagonist>
+ </name>
+ <exterior>
+ <material>glass</material>
+ <colour>
+ <night>black</night>
+ <day>transparent</day>
+ </colour>
+ </exterior>
+ <width>
+ <value>64</value>
+ <unit>metre</unit>
+ </width>
+ <length>
+ <value>64</value>
+ <unit>metre</unit>
+ </length>
+ <interstitial>0.3</interstitial>
+ <storeys>
+ <total>9</total>
+ <height>
+ <value>3</value>
+ <unit>m</unit>
+ </height>
+ </storeys>
+ </building>
+ <crop>
+ <name>tomato</name>
+ <weight>
+ <value>450</value>
+ <unit>g</unit>
+ </weight>
+ <height>
+ <value>1.5</value>
+ <unit>m</unit>
+ </height>
+ <diameter>
+ <value>0.6</value>
+ <unit>m</unit>
+ </diameter>
+ <energy>
+ <value>338</value>
+ <unit>kJ</unit>
+ </energy>
+ <yield>50</yield>
+ <harvests>5</harvests>
+ </crop>
+ <lamp>
+ <power>
+ <value>250</value>
+ <unit>W</unit>
+ </power>
+ <efficacy>
+ <value>303</value>
+ <unit>lm/W</unit>
+ </efficacy>
+ <length>
+ <value>1.22</value>
+ <unit>m</unit>
+ </length>
+ <width>
+ <value>0.28</value>
+ <unit>m</unit>
+ </width>
+ <height>
+ <value>0.17</value>
+ <unit>m</unit>
+ </height>
+ <coverage>
+ <fixture>
+ <value>1.2192</value>
+ <unit>m^2</unit>
+ </fixture>
+ <conveyance>
+ <ratio>0.35</ratio>
+ <power>
+ <value>5</value>
+ <unit>W</unit>
+ </power>
+ </conveyance>
+ </coverage>
+ </lamp>
+ <cost>
+ <electricity>
+ <value>11.27</value>
+ <unit>¢/kWh</unit>
+ <usage>
+ <value>12</value>
+ <unit>hours/day</unit>
+ </usage>
+ </electricity>
+ </cost>
+ <income>
+ <consultants>
+ <annual>
+ <value>517412</value>
+ <unit>nuvocoin</unit>
+ </annual>
+ <workforce>
+ <quantity>50</quantity>
+ <stipend>
+ <value>12</value>
+ <unit>per cent</unit>
+ </stipend>
+ </workforce>
+ </consultants>
+ </income>
+</farm>
+<heading>
+ <ch_01>Till</ch_01>
+ <ch_02>Sow</ch_02>
+ <ch_03>Seed</ch_03>
+ <ch_04>Germinate</ch_04>
+ <ch_05>Grow</ch_05>
+ <ch_06>Shoot</ch_06>
+ <ch_07>Bud</ch_07>
+ <ch_08>Bloom</ch_08>
+ <ch_09>Pollinate</ch_09>
+ <ch_10>Fruit</ch_10>
+ <ch_11>Harvest</ch_11>
+ <ch_12>Deliver</ch_12>
+ <ch_13>Spoil</ch_13>
+ <ch_14>Revolt</ch_14>
+ <ch_15>Compost</ch_15>
+ <ch_16>Burn</ch_16>
+ <ch_17>Ash</ch_17>
+ <ch_18>Release</ch_18>
+ <ch_19>End Notes</ch_19>
+ <ch_20>Characters</ch_20>
+</heading>
+<inference>
+ <unit>per cent</unit>
+ <min>10</min>
+ <ch_sow>84.35</ch_sow>
+ <ch_seed>63.41</ch_seed>
+ <ch_germinate>38.47</ch_germinate>
+ <ch_grow>25.39</ch_grow>
+ <ch_shoot>15.26</ch_shoot>
+ <ch_bloom>11.13</ch_bloom>
+ <ch_pollinate>2.05</ch_pollinate>
+ <ch_harvest>95</ch_harvest>
+ <ch_delivery>98.49</ch_delivery>
+</inference>
+<palette>
+ <hyperlink>6c984c</hyperlink>
+ <headers>aeaeae</headers>
+ <body>2e2e2e</body>
+ <accent>88b2d4</accent>
+ <fill>9f9f9f</fill>
+ <lightfill>cacaca</lightfill>
+</palette>
+<link>
+ <tartarus>https://en.wikipedia.org/wiki/Tartarus</tartarus>
+ <exploits>https://www.google.ca/search?q=inurl:ftp+password+filetype:xls</exploits>
+ <atalanta>https://en.wikipedia.org/wiki/Atalanta</atalanta>
+ <detain>https://goo.gl/RCNuOQ</detain>
+ <ceramics>https://en.wikipedia.org/wiki/Transparent_ceramics</ceramics>
+ <algernon>https://en.wikipedia.org/wiki/Flowers_for_Algernon</algernon>
+ <neurogenesis>http://cshperspectives.cshlp.org/content/7/7/a018994.long</neurogenesis>
+ <memristor>http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.404.9037&amp;rep=rep1&amp;type=pdf</memristor>
+ <surveillance>https://www.youtube.com/watch?v=XEVlyP4_11M#t=1487</surveillance>
+ <tor>https://www.torproject.org</tor>
+ <hydra>https://en.wikipedia.org/wiki/Lernaean_Hydra</hydra>
+ <foliage>http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3691134</foliage>
+ <drake>http://www.bbc.com/future/story/20120821-how-many-alien-worlds-exist</drake>
+ <fermi>https://arxiv.org/pdf/1404.0204v1.pdf</fermi>
+ <face>https://www.youtube.com/watch?v=ladqJQLR2bA</face>
+ <expenditures>http://wikipedia.org/wiki/List_of_countries_by_military_expenditures</expenditures>
+ <money>
+ <verify>https://newjersey.mylicense.com/verification_4_6</verify>
+ <register>https://edrs.nj.gov/edrs/loadRegisterNewUser.do</register>
+ <banking>https://okpay.com</banking>
+ <certificate>https://www.cdc.gov/nchs/data/dvs/death11-03final-acc.pdf</certificate>
+ <cryptocurrency>https://en.wikipedia.org/wiki/List_of_cryptocurrencies</cryptocurrency>
+ </money>
+ <governance>http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2003531</governance>
+ <asimov>https://en.wikipedia.org/wiki/Three_Laws_of_Robotics</asimov>
+ <clarke>https://en.wikipedia.org/wiki/Clarke&#39;s_three_laws</clarke>
+ <aeroboard>http://jetpackaviation.com</aeroboard>
+ <hoverboard>https://www.youtube.com/watch?v=WQzLrvz4DKQ</hoverboard>
+ <eyes_five>https://en.wikipedia.org/wiki/Five_Eyes</eyes_five>
+ <eyes_nine>https://www.privacytools.io</eyes_nine>
+ <eyes_fourteen>http://electrospaces.blogspot.nl/2013/12/14-eyes-are-3rd-party-partners-forming.html</eyes_fourteen>
+ <tourism>http://www.spacefuture.com/archive/investigation_on_the_economic_and_technological_feasibiity_of_commercial_passenger_transportation_into_leo.shtml</tourism>
+ <speech>https://github.com/kaldi-asr/kaldi</speech>
+ <behaviour>https://www.csoonline.com/article/2223400/microsoft-subnet/mind-s-eye-surveillance-to-watch--identify-and-predict-human-behavior-from-video.html</behaviour>
+ <borer>https://www.osti.gov/scitech/servlets/purl/1169951</borer>
+ <universe>https://physics.stackexchange.com/a/68346/2421</universe>
+ <god>
+ <thunder>http://www.ancientpages.com/2016/01/31/catequil-cultural-hero-and-inca-god-of-thunder-and-lightning</thunder>
+ </god>
+</link>
+<food>
+ <intake>
+ <weight>
+ <unit>kilogram</unit>
+ <value>0.378432</value>
+ <frequency>day</frequency>
+ </weight>
+ <calories>
+ <unit>kcal</unit>
+ <value>2920.05</value>
+ <frequency>day</frequency>
+ </calories>
+ </intake>
+</food>
+<parable>
+ <labour>
+ <protagonist>
+ <name>Obrero</name>
+ </protagonist>
+ </labour>
+</parable>
+</root>
index.xsl
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
+ <xsl:output omit-xml-declaration="yes" />
+ <xsl:output method="html" indent="no"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:param name="minify" />
+
+ <xsl:template match="/">
+ <xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html&gt;</xsl:text>
+ <html lang="en">
+ <head>
+ <xsl:apply-templates mode="head" />
+ </head>
+ <body>
+ <div class="page">
+ <header class="section header">
+ <xsl:apply-templates mode="header" />
+ </header>
+ <nav class="section menu">
+ <xsl:apply-templates mode="menu" />
+ </nav>
+ <main class="section content">
+ <xsl:apply-templates mode="content" />
+ </main>
+ <footer class="section footer">
+ <xsl:apply-templates mode="footer" />
+ </footer>
+ </div>
+ <xsl:apply-templates select="." mode="scripts" />
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="head">
+ <meta
+ name="viewport"
+ content="width=device-width,initial-scale=1user-scalable=yes" />
+ <meta
+ http-equiv="X-UA-Compatible"
+ content="IE=edge" />
+ <meta
+ name="description"
+ content="A hard sci-fi novel about automated food production, sentient machines, and surveillance societies." />
+
+ <link
+ rel="icon" type="image/png" sizes="16x16"
+ href="/favicon/favicon-16x16.png" />
+ <link
+ rel="icon" type="image/png" sizes="32x32"
+ href="/favicon/favicon-32x32.png" />
+
+ <xsl:apply-templates select="book/title" mode="head" />
+
+ <xsl:apply-templates select="." mode="normalize" />
+ <xsl:apply-templates select="." mode="styles" />
+ <xsl:apply-templates select="." mode="fonts" />
+ </xsl:template>
+
+ <xsl:template match="/root" mode="menu" />
+
+ <xsl:template match="/root" mode="header">
+ <xsl:apply-templates select="book/title" mode="header" />
+ </xsl:template>
+
+ <xsl:template match="/root" mode="content">
+ <div class="illustration">
+ <img
+ width="408" height="359"
+ src="images/farmer.jpg" alt="Android Farmer" />
+ </div>
+ <p class="quote">
+ <xsl:apply-templates select="c/protagonist/speech/tagline" mode="content" />
+ <xsl:text> ~ </xsl:text>
+ <xsl:apply-templates select="c/protagonist/name" mode="content" />
+ <xsl:text>, 2058.</xsl:text>
+ </p>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="footer" />
+
+ <xsl:template match="/root" mode="normalize">
+ <style media="screen" type="text/css">
+/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*# sourceMappingURL=normalize.min.css.map */
+ </style>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="styles">
+ <xsl:call-template name="stylesheet">
+ <xsl:with-param name="file" select="'simple'" />
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template match="/root" mode="fonts">
+ <link
+ href="//fonts.googleapis.com/css?family=Source+Sans+Pro:200|Libre+Baskerville"
+ rel="stylesheet" />
+ </xsl:template>
+
+ <xsl:template match="/root" mode="scripts" />
+
+ <xsl:template match="book/title" mode="head">
+ <title><xsl:apply-templates /></title>
+ </xsl:template>
+
+ <xsl:template match="book/title" mode="header">
+ <h1><xsl:apply-templates /></h1>
+ </xsl:template>
+
+ <xsl:template match="tagline" mode="content">
+ <q><xsl:apply-templates /></q>
+ </xsl:template>
+
+ <xsl:template match="protagonist/name" mode="content">
+ <xsl:value-of select="First" />
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="Family" />
+ </xsl:template>
+
+ <!-- Includes a stylesheet, optionally minified. -->
+ <xsl:template name="stylesheet">
+ <xsl:param name="file" />
+ <xsl:param name="relative" select="''" />
+
+ <link
+ rel="stylesheet" type="text/css" media="screen">
+ <xsl:attribute name="href">
+ <xsl:value-of select="$relative" />
+ <xsl:text>themes/</xsl:text>
+ <xsl:value-of select="$file" />
+ <xsl:value-of select="$minify" />
+ <xsl:text>.css</xsl:text>
+ </xsl:attribute>
+ </link>
+ </xsl:template>
+
+ <!-- Includes a script, optionally minified. -->
+ <xsl:template name="script">
+ <xsl:param name="file" />
+
+ <script defer="defer">
+ <xsl:attribute name="src">
+ <xsl:value-of select="$file" />
+ <xsl:value-of select="$minify" />
+ <xsl:text>.js</xsl:text>
+ </xsl:attribute>
+ </script>
+ </xsl:template>
+
+ <xsl:template match="*" />
+
+</xsl:stylesheet>
+
themes/calculator.css
+p.equation {
+ border: 1px solid #88b2d4;
+ border-radius: 8px;
+ background: #eee;
+}
+
+div.variables {
+ width: 100%;
+ display: table;
+}
+
+div.input, div.output {
+ display: table-cell;
+ vertical-align: top;
+}
+
+dl {
+ overflow: hidden;
+}
+
+dt, dd {
+ float: left;
+ margin: 0 0 1em;
+}
+
+dt {
+ color: #88b2d4;
+ width: 10%;
+ clear: left;
+}
+
+dd {
+ width: calc(90% - 1em);
+ margin-left: 1em;
+}
+
+dd:after {
+ content: '';
+ display: table;
+ clear: both;
+}
+
themes/calculator.min.css
-
+p.equation{border:1px solid #88b2d4;border-radius:8px;background:#eee}div.variables{width:100%;display:table}div.input,div.output{display:table-cell;vertical-align:top}dl{overflow:hidden}dt,dd{float:left;margin:0 0 1em}dt{color:#88b2d4;width:10%;clear:left}dd{width:calc(90% - 1em);margin-left:1em}dd:after{content:'';display:table;clear:both}
themes/form.css
+main > p {
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+form {
+ margin: 0 auto;
+ counter-reset: fieldsets
+}
+
+/* Number the fieldset steps. */
+fieldset legend::before {
+ content: counter(fieldsets);
+ counter-increment: fieldsets;
+
+ display: inline-block;
+ border-radius: 50%;
+ margin-right: 0.5em;
+ line-height: 1.6em;
+ text-align: center;
+
+ width: 1.5em;
+ background: #88b2d4;
+ box-shadow: 1px 1px 1px 0px rgba(50, 50, 50, 0.5);
+}
+
+/* Hide the number for total. */
+fieldset:last-of-type legend::before {
+ display: none;
+}
+
+fieldset legend {
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+}
+
+fieldset {
+ width: 65%;
+ margin: 0 auto;
+ background: #eee;
+ border-radius: 0.5em;
+ margin-bottom: 2em;
+ border: 1px solid #88b2d4;
+}
+
+div.subtotal p {
+ color: #88b2d4;
+ font-weight: bold;
+ text-align: center;
+}
+
+label {
+ display: inline-block;
+ width: 18.5em;
+ text-align: right;
+ padding-right: 1em;
+ margin-bottom: 0.5em;
+}
+
+/* Mobile Styles */
+@media only screen and (max-width: 400px) {
+ label {
+ text-align: left;
+ padding-right: 1em;
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
+ }
+}
+
+/* Hide spinners. */
+input[type="number"]::-webkit-outer-spin-button,
+input[type="number"]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+input[type="number"] {
+ -moz-appearance: textfield;
+}
+
+input, textarea {
+ border: 0.12em solid #cacaca;
+ border-radius: 0.5em;
+ padding: 0.25em;
+ width: 10em;
+}
+
+input:focus, textarea:focus {
+ outline: none;
+ border-color: #88b2d4;
+ box-shadow: 0 0 0.25em #88b2d4;
+ padding: 0.25em;
+ transition: box-shadow 0.2s linear;
+}
+
+input[readonly], input[readonly]:focus {
+ border: 0;
+ border-color: transparent;
+ cursor: default;
+ background-color: #ddd;
+ pointer-events: none;
+}
+
+button.submit {
+ display: block;
+ margin: auto;
+ margin-bottom: 1.5em;
+ padding: 0.5em;
+ border: 1px solid #88b2d4;
+ border-radius: 0.5em;
+ box-shadow: 1px 1px 1px 0px rgba(50, 50, 50, 0.5);
+}
+
themes/form.min.css
-
+main>p{padding-left:1em;padding-right:1em}form{margin:0 auto;counter-reset:fieldsets}fieldset legend::before{content:counter(fieldsets);counter-increment:fieldsets;display:inline-block;border-radius:50%;margin-right:.5em;line-height:1.6em;text-align:center;width:1.5em;background:#88b2d4;box-shadow:1px 1px 1px 0 rgba(50,50,50,0.5)}fieldset:last-of-type legend::before{display:none}fieldset legend{padding-left:.5em;padding-right:.5em}fieldset{width:65%;margin:0 auto;background:#eee;border-radius:.5em;margin-bottom:2em;border:1px solid #88b2d4}div.subtotal p{color:#88b2d4;font-weight:bold;text-align:center}label{display:inline-block;width:18.5em;text-align:right;padding-right:1em;margin-bottom:.5em}@media only screen and (max-width:400px){label{text-align:left;padding-right:1em;margin-top:.25em;margin-bottom:.25em}}input[type="number"]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type="number"]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type="number"]{-moz-appearance:textfield}input,textarea{border:.12em solid #cacaca;border-radius:.5em;padding:.25em;width:10em}input:focus,textarea:focus{outline:none;border-color:#88b2d4;box-shadow:0 0 .25em #88b2d4;padding:.25em;transition:box-shadow .2s linear}input[readonly],input[readonly]:focus{border:0;border-color:transparent;cursor:default;background-color:#ddd;pointer-events:none}
themes/simple.css
+* {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Libre Baskerville', serif;
+ color: #2e2e2e;
+ margin: 0 auto;
+}
+
+.page {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.section {
+ width: 100%;
+ justify-content: center;
+ align-items: center;
+}
+
+h1, h2, h3 {
+ font-family: 'Source Sans Pro', sans-serif;
+ color: #aeaeae;
+}
+
+h1 {
+ font-size: 3em;
+ font-weight: normal;
+ text-align: center;
+}
+
+h2 {
+ font-size: 2em;
+}
+
+h3 {
+ font-size: 1.5em;
+}
+
+.illustration {
+ display: block;
+ margin: 0 auto;
+ text-align: center;
+}
+
+p {
+ line-height: 1.6em;
+}
+
+p.quote {
+ text-align: center;
+}
+
+q {
+ quotes: "“" "”" "“" "”";
+}
+
+q:before {
+ content: open-quote;
+}
+
+q:after {
+ content: close-quote;
+}
+
+a {
+ color: #6c984c;
+ text-decoration: none;
+}
+
+/* Mobile Styles */
+@media only screen and (max-width: 400px) {
+ .illustration img {
+ width: 100%;
+ height: auto;
+ display: block;
+ margin: 0 auto;
+ }
+
+ h1 {
+ font-size: 2em;
+ }
+
+ h2 {
+ font-size: 1.5em;
+ }
+
+ h3 {
+ font-size: 1em;
+ }
+}
+
+/* Tablet Styles */
+@media only screen and (min-width: 401px) and (max-width: 960px) {
+}
+
+/* Desktop Styles */
+@media only screen and (min-width: 961px) {
+ .page {
+ width: 800px;
+ max-width: 800px;
+ margin: 0 auto;
+ }
+}
+
themes/simple.min.css
-
+*{box-sizing:border-box}body{font-family:'Libre Baskerville',serif;color:#2e2e2e;margin:0 auto}.page{display:flex;flex-wrap:wrap}.section{width:100%;justify-content:center;align-items:center}h1,h2,h3{font-family:'Source Sans Pro',sans-serif;color:#aeaeae}h1{font-size:3em;font-weight:normal;text-align:center}h2{font-size:2em}h3{font-size:1.5em}.illustration{display:block;margin:0 auto;text-align:center}p{line-height:1.6em}p.quote{text-align:center}q{quotes:"\00201c" "\00201d" "\00201c" "\00201d"}q:before{content:open-quote}q:after{content:close-quote}a{color:#6c984c;text-decoration:none}@media only screen and (max-width:400px){.illustration img{width:100%;height:auto;display:block;margin:0 auto}h1{font-size:2em}h2{font-size:1.5em}h3{font-size:1em}}@media only screen and (min-width:401px) and (max-width:960px){}@media only screen and (min-width:961px){.page{width:800px;max-width:800px;margin:0 auto}}

Adds calculators, themes, styles, and stylesheets

Author djarvis <email>
Date 2024-11-26 20:02:10 GMT-0800
Commit eff2e9181a5d380a374abfe6438579ceb352159a
Parent 15ac2d3
Delta 4127 lines added, 5 lines removed, 4122-line increase