Full Code of worrydream/ClimateChange for AI

master 36eaa26dab2b cached
31 files
260.5 KB
70.9k tokens
71 symbols
1 requests
Download .txt
Showing preview only (272K chars total). Download the full file or copy to clipboard to get everything.
Repository: worrydream/ClimateChange
Branch: master
Commit: 36eaa26dab2b
Files: 31
Total size: 260.5 KB

Directory structure:
gitextract_g6xedxv7/

├── Fonts/
│   ├── fake_receipt.css
│   ├── hcb.css
│   ├── hcm.css
│   └── sourcesanspro.css
├── Lib/
│   ├── Tangle.js
│   ├── Touchable.js
│   └── sprintf.js
├── Notes/
│   ├── 01-private.txt
│   ├── 02-solar-land.txt
│   ├── 03-all-the-batteries.txt
│   ├── 03-carbon-budget.txt
│   ├── 03-demand-curve.html
│   └── 06-clunker.txt
├── README.md
├── Script/
│   ├── autocomplete-video.js
│   ├── carbon-budget.js
│   ├── chart-data.js
│   ├── charts.js
│   ├── clunker.js
│   ├── main.js
│   └── previews.js
├── Video/
│   ├── 05-dynamic-0.webm
│   ├── 05-dynamic-1.webm
│   ├── 05-dynamic-2.webm
│   ├── 05-dynamic-3.webm
│   ├── 05-dynamic-4.webm
│   ├── 05-dynamic-5.webm
│   └── 06-autocomplete.webm
├── data.html
├── index.html
└── style.css

================================================
FILE CONTENTS
================================================

================================================
FILE: Fonts/fake_receipt.css
================================================
@font-face {
    font-family: 'fake_receiptregular';
    src: url('fake_receipt-webfont.eot');
    src: url('fake_receipt-webfont.eot?#iefix') format('embedded-opentype'),
         url('fake_receipt-webfont.woff2') format('woff2'),
         url('fake_receipt-webfont.woff') format('woff'),
         url('fake_receipt-webfont.ttf') format('truetype'),
         url('fake_receipt-webfont.svg#fake_receiptregular') format('svg');
    font-weight: normal;
    font-style: normal;
}


================================================
FILE: Fonts/hcb.css
================================================

@font-face {
    font-family: 'hcb';
    src: url('hcb-webfont.eot');
    src: url('hcb-webfont.eot?#iefix') format('embedded-opentype'),
         url('hcb-webfont.woff2') format('woff2'),
         url('hcb-webfont.woff') format('woff'),
         url('hcb-webfont.ttf') format('truetype'),
         url('hcb-webfont.svg#helvetica_condensedbold') format('svg');
    font-weight: normal;
    font-style: normal;

}

================================================
FILE: Fonts/hcm.css
================================================
@font-face {
    font-family: 'hcm';
    src: url('hcm-webfont.eot');
    src: url('hcm-webfont.eot?#iefix') format('embedded-opentype'),
         url('hcm-webfont.woff2') format('woff2'),
         url('hcm-webfont.woff') format('woff'),
         url('hcm-webfont.ttf') format('truetype'),
         url('hcm-webfont.svg#helvetica_condensedmedium') format('svg');
    font-weight: normal;
    font-style: normal;
}


================================================
FILE: Fonts/sourcesanspro.css
================================================

@font-face {
    font-family: 'Source Sans Pro';
    src: url('sourcesanspro-bold-webfont.eot');
    src: url('sourcesanspro-bold-webfont.eot?#iefix') format('embedded-opentype'),
         url('sourcesanspro-bold-webfont.woff2') format('woff2'),
         url('sourcesanspro-bold-webfont.woff') format('woff'),
         url('sourcesanspro-bold-webfont.ttf') format('truetype'),
         url('sourcesanspro-bold-webfont.svg#source_sans_probold') format('svg');
    font-weight: bold;
    font-style: normal;

}


@font-face {
    font-family: 'Source Sans Pro';
    src: url('sourcesanspro-boldit-webfont.eot');
    src: url('sourcesanspro-boldit-webfont.eot?#iefix') format('embedded-opentype'),
         url('sourcesanspro-boldit-webfont.woff2') format('woff2'),
         url('sourcesanspro-boldit-webfont.woff') format('woff'),
         url('sourcesanspro-boldit-webfont.ttf') format('truetype'),
         url('sourcesanspro-boldit-webfont.svg#source_sans_probold_italic') format('svg');
    font-weight: bold;
    font-style: italic;

}


@font-face {
    font-family: 'Source Sans Pro';
    src: url('sourcesanspro-it-webfont.eot');
    src: url('sourcesanspro-it-webfont.eot?#iefix') format('embedded-opentype'),
         url('sourcesanspro-it-webfont.woff2') format('woff2'),
         url('sourcesanspro-it-webfont.woff') format('woff'),
         url('sourcesanspro-it-webfont.ttf') format('truetype'),
         url('sourcesanspro-it-webfont.svg#source_sans_proitalic') format('svg');
    font-weight: normal;
    font-style: italic;

}

@font-face {
    font-family: 'Source Sans Pro';
    src: url('sourcesanspro-regular-webfont.eot');
    src: url('sourcesanspro-regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('sourcesanspro-regular-webfont.woff2') format('woff2'),
         url('sourcesanspro-regular-webfont.woff') format('woff'),
         url('sourcesanspro-regular-webfont.ttf') format('truetype'),
         url('sourcesanspro-regular-webfont.svg#source_sans_proregular') format('svg');
    font-weight: normal;
    font-style: normal;

}

================================================
FILE: Lib/Tangle.js
================================================
//
//  Tangle.js
//  Tangle 0.1.0
//
//  Created by Bret Victor on 5/2/10.
//  (c) 2011 Bret Victor.  MIT open-source license.
//
//  ------ model ------
//
//  var tangle = new Tangle(rootElement, model);
//  tangle.setModel(model);
//
//  ------ variables ------
//
//  var value = tangle.getValue(variableName);
//  tangle.setValue(variableName, value);
//  tangle.setValues({ variableName:value, variableName:value });
//
//  ------ UI components ------
//
//  Tangle.classes.myClass = {
//     initialize: function (element, options, tangle, variable) { ... },
//     update: function (element, value) { ... }
//  };
//  Tangle.formats.myFormat = function (value) { return "..."; };
//

var Tangle = this.Tangle = function (rootElement, modelClass) {

    var tangle = this;
    tangle.element = rootElement;
    tangle.setModel = setModel;
    tangle.getValue = getValue;
    tangle.setValue = setValue;
    tangle.setValues = setValues;

    var _model;
    var _nextSetterID = 0;
    var _setterInfosByVariableName = {};   //  { varName: { setterID:7, setter:function (v) { } }, ... }
    var _varargConstructorsByArgCount = [];


    //----------------------------------------------------------
    //
    // construct

    initializeElements();
    setModel(modelClass);
    return tangle;


    //----------------------------------------------------------
    //
    // elements

    function initializeElements() {
        var elements = rootElement.getElementsByTagName("*");
        var interestingElements = [];
        
        // build a list of elements with class or data-var attributes
        
        for (var i = 0, length = elements.length; i < length; i++) {
            var element = elements[i];
            if (element.getAttribute("class") || element.getAttribute("data-var")) {
                interestingElements.push(element);
            }
        }

        // initialize interesting elements in this list.  (Can't traverse "elements"
        // directly, because elements is "live", and views that change the node tree
        // will change elements mid-traversal.)
        
        for (var i = 0, length = interestingElements.length; i < length; i++) {
            var element = interestingElements[i];
            
            var varNames = null;
            var varAttribute = element.getAttribute("data-var");
            if (varAttribute) { varNames = varAttribute.split(" "); }

            var views = null;
            var classAttribute = element.getAttribute("class");
            if (classAttribute) {
                var classNames = classAttribute.split(" ");
                views = getViewsForElement(element, classNames, varNames);
            }
            
            if (!varNames) { continue; }
            
            var didAddSetter = false;
            if (views) {
                for (var j = 0; j < views.length; j++) {
                    if (!views[j].update) { continue; }
                    addViewSettersForElement(element, varNames, views[j]);
                    didAddSetter = true;
                }
            }
            
            if (!didAddSetter) {
                var formatAttribute = element.getAttribute("data-format");
                var formatter = getFormatterForFormat(formatAttribute, varNames);
                addFormatSettersForElement(element, varNames, formatter);
            }
        }
    }
            
    function getViewsForElement(element, classNames, varNames) {   // initialize classes
        var views = null;
        
        for (var i = 0, length = classNames.length; i < length; i++) {
            var clas = Tangle.classes[classNames[i]];
            if (!clas) { continue; }
            
            var options = getOptionsForElement(element);
            var args = [ element, options, tangle ];
            if (varNames) { args = args.concat(varNames); }
            
            var view = constructClass(clas, args);
            
            if (!views) { views = []; }
            views.push(view);
        }
        
        return views;
    }
    
    function getOptionsForElement(element) {   // might use dataset someday
        var options = {};

        var attributes = element.attributes;
        var regexp = /^data-[\w\-]+$/;

        for (var i = 0, length = attributes.length; i < length; i++) {
            var attr = attributes[i];
            var attrName = attr.name;
            if (!attrName || !regexp.test(attrName)) { continue; }
            
            options[attrName.substr(5)] = attr.value;
        }
         
        return options;   
    }
    
    function constructClass(clas, args) {
        if (typeof clas !== "function") {  // class is prototype object
            var View = function () { };
            View.prototype = clas;
            var view = new View();
            if (view.initialize) { view.initialize.apply(view,args); }
            return view;
        }
        else {  // class is constructor function, which we need to "new" with varargs (but no built-in way to do so)
            var ctor = _varargConstructorsByArgCount[args.length];
            if (!ctor) {
                var ctorArgs = [];
                for (var i = 0; i < args.length; i++) { ctorArgs.push("args[" + i + "]"); }
                var ctorString = "(function (clas,args) { return new clas(" + ctorArgs.join(",") + "); })";
                ctor = eval(ctorString);   // nasty
                _varargConstructorsByArgCount[args.length] = ctor;   // but cached
            }
            return ctor(clas,args);
        }
    }
    

    //----------------------------------------------------------
    //
    // formatters

    function getFormatterForFormat(formatAttribute, varNames) {
        if (!formatAttribute) { formatAttribute = "default"; }

        var formatter = getFormatterForCustomFormat(formatAttribute, varNames);
        if (!formatter) { formatter = getFormatterForSprintfFormat(formatAttribute, varNames); }
        if (!formatter) { log("Tangle: unknown format: " + formatAttribute); formatter = getFormatterForFormat(null,varNames); }

        return formatter;
    }
        
    function getFormatterForCustomFormat(formatAttribute, varNames) {
        var components = formatAttribute.split(" ");
        var formatName = components[0];
        if (!formatName) { return null; }
        
        var format = Tangle.formats[formatName];
        if (!format) { return null; }
        
        var formatter;
        var params = components.slice(1);
        
        if (varNames.length <= 1 && params.length === 0) {  // one variable, no params
            formatter = format;
        }
        else if (varNames.length <= 1) {  // one variable with params
            formatter = function (value) {
                var args = [ value ].concat(params);
                return format.apply(null, args);
            };
        }
        else {  // multiple variables
            formatter = function () {
                var values = getValuesForVariables(varNames);
                var args = values.concat(params);
                return format.apply(null, args);
            };
        }
        return formatter;
    }
    
    function getFormatterForSprintfFormat(formatAttribute, varNames) {
        if (!sprintf || !formatAttribute.match(/\%/)) { return null; }

        var formatter;
        if (varNames.length <= 1) {  // one variable
            formatter = function (value) {
                return sprintf(formatAttribute, value);
            };
        }
        else {
            formatter = function (value) {  // multiple variables
                var values = getValuesForVariables(varNames);
                var args = [ formatAttribute ].concat(values);
                return sprintf.apply(null, args);
            };
        }
        return formatter;
    }

    
    //----------------------------------------------------------
    //
    // setters
    
    function addViewSettersForElement(element, varNames, view) {   // element has a class with an update method
        var setter;
        if (varNames.length <= 1) {
            setter = function (value) { view.update(element, value); };
        }
        else {
            setter = function () {
                var values = getValuesForVariables(varNames);
                var args = [ element ].concat(values);
                view.update.apply(view,args);
            };
        }

        addSetterForVariables(setter, varNames);
    }

    function addFormatSettersForElement(element, varNames, formatter) {  // tangle is injecting a formatted value itself
        var span = null;
        var setter = function (value) {
            if (!span) { 
                span = document.createElement("span");
                element.insertBefore(span, element.firstChild);
            }
            span.innerHTML = formatter(value);
        };

        addSetterForVariables(setter, varNames);
    }
    
    function addSetterForVariables(setter, varNames) {
        var setterInfo = { setterID:_nextSetterID, setter:setter };
        _nextSetterID++;

        for (var i = 0; i < varNames.length; i++) {
            var varName = varNames[i];
            if (!_setterInfosByVariableName[varName]) { _setterInfosByVariableName[varName] = []; }
            _setterInfosByVariableName[varName].push(setterInfo);
        }
    }

    function applySettersForVariables(varNames) {
        var appliedSetterIDs = {};  // remember setterIDs that we've applied, so we don't call setters twice
    
        for (var i = 0, ilength = varNames.length; i < ilength; i++) {
            var varName = varNames[i];
            var setterInfos = _setterInfosByVariableName[varName];
            if (!setterInfos) { continue; }
            
            var value = _model[varName];
            
            for (var j = 0, jlength = setterInfos.length; j < jlength; j++) {
                var setterInfo = setterInfos[j];
                if (setterInfo.setterID in appliedSetterIDs) { continue; }  // if we've already applied this setter, move on
                appliedSetterIDs[setterInfo.setterID] = true;
                
                setterInfo.setter(value);
            }
        }
    }
    

    //----------------------------------------------------------
    //
    // variables

    function getValue(varName) {
        var value = _model[varName];
        if (value === undefined) { log("Tangle: unknown variable: " + varName);  return 0; }
        return value;
    }

    function setValue(varName, value) {
        var obj = {};
        obj[varName] = value;
        setValues(obj);
    }

    function setValues(obj) {
        var changedVarNames = [];

        for (var varName in obj) {
            var value = obj[varName];
            var oldValue = _model[varName];
            if (oldValue === undefined) { log("Tangle: setting unknown variable: " + varName);  continue; }
            if (oldValue === value) { continue; }  // don't update if new value is the same

            _model[varName] = value;
            changedVarNames.push(varName);
        }
        
        if (changedVarNames.length) {
            applySettersForVariables(changedVarNames);
            updateModel();
        }
    }
    
    function getValuesForVariables(varNames) {
        var values = [];
        for (var i = 0, length = varNames.length; i < length; i++) {
            values.push(getValue(varNames[i]));
        }
        return values;
    }

                    
    //----------------------------------------------------------
    //
    // model

    function setModel(modelClass) {
        var ModelClass = function () { };
        ModelClass.prototype = modelClass;
        _model = new ModelClass;

        updateModel(true);  // initialize and update
    }
    
    function updateModel(shouldInitialize) {
        var ShadowModel = function () {};  // make a shadow object, so we can see exactly which properties changed
        ShadowModel.prototype = _model;
        var shadowModel = new ShadowModel;
        
        if (shouldInitialize) { shadowModel.initialize(); }
        shadowModel.update();
        
        var changedVarNames = [];
        for (var varName in shadowModel) {
            if (!shadowModel.hasOwnProperty(varName)) { continue; }
            if (_model[varName] === shadowModel[varName]) { continue; }
            
            _model[varName] = shadowModel[varName];
            changedVarNames.push(varName);
        }
        
        applySettersForVariables(changedVarNames);
    }


    //----------------------------------------------------------
    //
    // debug

    function log (msg) {
        if (window.console) { window.console.log(msg); }
    }

};  // end of Tangle


//----------------------------------------------------------
//
// components

Tangle.classes = {};
Tangle.formats = {};

Tangle.formats["default"] = function (value) { return "" + value; };



================================================
FILE: Lib/Touchable.js
================================================
//
//  Touchable.js
//
//  Created by Bret Victor on 3/10/11.
//  (c) 2011 Bret Victor.  MIT open-source license.
//

function makeTouchable (el, delegate) {

    var initialize = function () {
        el.addEventListener("mousedown", mouseDown);
        el.addEventListener("touchstart", touchStart);
    };
    
	var mouseDown = function (e) {
		e.preventDefault();
        document.body.addEventListener("mousemove", mouseMove);
        document.body.addEventListener("mouseup", mouseUp);
        delegate.touchDown(e, e.pageX, e.pageY);
    };

	var mouseMove = function (e) {
		e.preventDefault();
        delegate.touchMove(e, e.pageX, e.pageY);
    };

	var mouseUp = function (e) {
		e.preventDefault();
        delegate.touchUp(e, e.pageX, e.pageY);
        document.body.removeEventListener("mousemove", mouseMove);
        document.body.removeEventListener("mouseup", mouseUp);
    };
    
    var touchStart = function (e) {
        e.preventDefault();
        document.body.addEventListener("touchmove", touchMove);
        document.body.addEventListener("touchend", touchEnd);
        document.body.addEventListener("touchcancel", touchCancel);
        var pt = getTouchPoint(e);
        delegate.touchDown(e,pt[0],pt[1]);
	};

	var touchMove = function (e) {
		e.preventDefault();
        var pt = getTouchPoint(e);
        delegate.touchMove(e,pt[0],pt[1]);
    };
	
	var touchEnd = function (e) {
		e.preventDefault();
        var pt = getTouchPoint(e);
        delegate.touchUp(e,pt[0],pt[1]);
        document.body.removeEventListener("touchmove", touchMove);
        document.body.removeEventListener("touchend", touchEnd);
        document.body.removeEventListener("touchcancel", touchCancel);
	};

	var touchCancel = function (e) {
	   touchEnd(e);
	};
	
	var getTouchPoint = function (e) {
	   if (e.pageX !== undefined) { return [e.pageX, e.pageY]; }
	   if (e.targetTouches && e.targetTouches[0]) { return [e.targetTouches[0].pageX, e.targetTouches[0].pageY]; }
	   return [0,0];
	};
	
	initialize();
}


================================================
FILE: Lib/sprintf.js
================================================
/**
sprintf() for JavaScript 0.7-beta1
http://www.diveintojavascript.com/projects/javascript-sprintf

Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of sprintf() for JavaScript nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Changelog:
2010.09.06 - 0.7-beta1
  - features: vsprintf, support for named placeholders
  - enhancements: format cache, reduced global namespace pollution

2010.05.22 - 0.6:
 - reverted to 0.4 and fixed the bug regarding the sign of the number 0
 Note:
 Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)
 who warned me about a bug in 0.5, I discovered that the last update was
 a regress. I appologize for that.

2010.05.09 - 0.5:
 - bug fix: 0 is now preceeded with a + sign
 - bug fix: the sign was not at the right position on padded results (Kamal Abdali)
 - switched from GPL to BSD license

2007.10.21 - 0.4:
 - unit test and patch (David Baird)

2007.09.17 - 0.3:
 - bug fix: no longer throws exception on empty paramenters (Hans Pufal)

2007.09.11 - 0.2:
 - feature: added argument swapping

2007.04.03 - 0.1:
 - initial release
**/

var sprintf = (function() {
	function get_type(variable) {
		return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
	}
	function str_repeat(input, multiplier) {
		for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
		return output.join('');
	}

	var str_format = function() {
		if (!str_format.cache.hasOwnProperty(arguments[0])) {
			str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
		}
		return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
	};

	str_format.format = function(parse_tree, argv) {
		var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
		for (i = 0; i < tree_length; i++) {
			node_type = get_type(parse_tree[i]);
			if (node_type === 'string') {
				output.push(parse_tree[i]);
			}
			else if (node_type === 'array') {
				match = parse_tree[i]; // convenience purposes only
				if (match[2]) { // keyword argument
					arg = argv[cursor];
					for (k = 0; k < match[2].length; k++) {
						if (!arg.hasOwnProperty(match[2][k])) {
							throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
						}
						arg = arg[match[2][k]];
					}
				}
				else if (match[1]) { // positional argument (explicit)
					arg = argv[match[1]];
				}
				else { // positional argument (implicit)
					arg = argv[cursor++];
				}

				if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
					throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
				}
				switch (match[8]) {
					case 'b': arg = arg.toString(2); break;
					case 'c': arg = String.fromCharCode(arg); break;
					case 'd': arg = parseInt(arg, 10); break;
					case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
					case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
					case 'o': arg = arg.toString(8); break;
					case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
					case 'u': arg = Math.abs(arg); break;
					case 'x': arg = arg.toString(16); break;
					case 'X': arg = arg.toString(16).toUpperCase(); break;
				}
				arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
				pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
				pad_length = match[6] - String(arg).length;
				pad = match[6] ? str_repeat(pad_character, pad_length) : '';
				output.push(match[5] ? arg + pad : pad + arg);
			}
		}
		return output.join('');
	};

	str_format.cache = {};

	str_format.parse = function(fmt) {
		var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
		while (_fmt) {
			if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
				parse_tree.push(match[0]);
			}
			else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
				parse_tree.push('%');
			}
			else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
				if (match[2]) {
					arg_names |= 1;
					var field_list = [], replacement_field = match[2], field_match = [];
					if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
						field_list.push(field_match[1]);
						while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
							if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else {
								throw('[sprintf] huh?');
							}
						}
					}
					else {
						throw('[sprintf] huh?');
					}
					match[2] = field_list;
				}
				else {
					arg_names |= 2;
				}
				if (arg_names === 3) {
					throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
				}
				parse_tree.push(match);
			}
			else {
				throw('[sprintf] huh?');
			}
			_fmt = _fmt.substring(match[0].length);
		}
		return parse_tree;
	};

	return str_format;
})();

var vsprintf = function(fmt, argv) {
	argv.unshift(fmt);
	return sprintf.apply(null, argv);
};


================================================
FILE: Notes/01-private.txt
================================================
Cleantech funding numbers are from the PriceWaterhouseCoopers Money Tree reports.

2009-2011: see figure 6 in http://worrydream.com/ClimateChange/refs/moneytree-tech-summary-Q4-2011.pdf
2012-2013: see figure 5 in http://worrydream.com/ClimateChange/refs/pwc-moneytree-cleantech-venture-funding-q4-2013.pdf
2014:      see figure 5 in http://worrydream.com/ClimateChange/refs/Cleantech_2015-1.pdf


================================================
FILE: Notes/02-solar-land.txt
================================================
land in us
    2,300,000 square miles of land
        http://www.ers.usda.gov/amber-waves/2012-march/data-feature-how-is-land-used.aspx#.Vh7T37SXL5c

land devoted to agriculture
    1,173,000 square miles of farm (51%)
        http://www.ers.usda.gov/amber-waves/2012-march/data-feature-how-is-land-used.aspx#.Vh7T37SXL5c

land devoted to roads
    17,929 square miles of road (0.6%)
        http://www.artba.org/about/transportation-faqs/#11

land required for PVs to power all US energy
    38,900 trillion btu/year = 11,400,464 GWh/year
        https://flowcharts.llnl.gov/content/assets/images/energy/us/Energy_US_2014.png
    at 3.0 acres/GWh/year
        http://www.nrel.gov/docs/fy13osti/56290.pdf table 4
    = 34.2 million acres
    = 53,400 square miles (1.8%)

land required for PVs to power all US electricity
    3,700,000 GWh/year
        http://www.eia.gov/electricity/annual/html/epa_01_02.html
    at 3.0 acres/GWh/year
        http://www.nrel.gov/docs/fy13osti/56290.pdf table 4
    = 11.1 million acres = 17,300 square miles (0.58%)
    


================================================
FILE: Notes/03-all-the-batteries.txt
================================================
Bill Gates: Innovating to zero, 12:00
https://www.ted.com/talks/bill_gates
"All the batteries on Earth can store only 10 minutes of the world's electricity needs."

Danielle Fong, private correspondence:
"There's about 100 GWh of batteries produced every year. These batteries last about 3-5 years, but let's be generous and suppose they last for 10 years -- leaving 1000 GWh of batteries available for storage. The world uses about 10 TW on average, or 240,000 GWh per day, or 240x the total amount of battery storage used per day. That's actually about 6 minutes of storage -- so maybe Bill has been even more generous than I."

(Her references are in here: http://worrydream.com/ClimateChange/refs/DanielleFong-GrowthRateRequiredInEnergyStorage.pdf)



================================================
FILE: Notes/03-carbon-budget.txt
================================================
carbon emissions 1950-2013:
    http://www.globalcarbonproject.org/carbonbudget/14/data.htm
    Global_Carbon_Budget_2014_v1.1.xlsx
    C. Le Quere, et al, Global Carbon Budget 2014. Earth System Science Data, doi:10.5194/essd-7-47-2015
    
carbon emissions 2014-2050:
    interpolated from "IEA 4DS" scenario
    http://www.iea.org/etp/explore/
    
carbon budget 2000-2050:
    http://www.carbontracker.org/wp-content/uploads/2014/09/Unburnable-Carbon-Full-rev2-1.pdf
    Carbon Tracker Initiative, Unburnable Carbon
    (citing http://www.nature.com/nature/journal/v458/n7242/full/nature08017.html)
    "The Potsdam Climate Institute has calculated a global carbon budget for the world to stay below 2C of warming. This uses probabilistic climate change modelling to calculate the total volume of carbon dioxide (CO2) emissions permitted in the first half of the 21st century to achieve the target. This revealed that to reduce the chance of exceeding 2 C warming to 20%, the global carbon budget for 2000-2050 is 886 GtCO2."
    
carbon budget 2015-2050:
    From the 886 GtCO2 budget for 2000-2050, I subtracted out the 440 GtCO2 already spent 2000-2014, leaving 446 GtCO2 remaining for 2015-2050.



================================================
FILE: Notes/03-demand-curve.html
================================================
<!DOCTYPE html>
<html><head>
    <meta charset="UTF-8">
    <base target="_top">
    <style>
        body {
            font: normal 14px/1.4 "Helvetica Neue", sans-serif;
            margin-left:20px;
            width:700px;
        }
    </style>
</head>

<body>

<p>These are screenshots from the California ISO's <a href="http://www.caiso.com/Pages/TodaysOutlook.aspx">Today's Outlook</a> page, taken at the end of Oct 22, 2015.</p>

<p>As far as I can tell, the ISO website doesn't offer historical data.</p>

<hr>

<p><img src="03-demand-curve-1.png"></p>
<p><img src="03-demand-curve-2.png"></p>
<p><img src="03-demand-curve-3.png"></p>
    
</body></html>


================================================
FILE: Notes/06-clunker.txt
================================================
You can download the raw data, cleaned data, and add-up-the-distribution script at

    http://worrydream.com/ClimateChange/Notes/06-clunker.zip
    

MPG data for all cars of a given model year is at 
    
    https://www.fueleconomy.gov/feg/download.shtml
    
I used the "combined MPG" column, which I believe assumes 55% city-miles and 45% highway-miles, harmonic average.


For "MPG distribution for cars currently on the road (in 2008)", I added up the data from the years 1984-2004.  Most cars earlier than 1984 won't be on the road, and cars later than 2004 are unlikely to be sold so soon.  Cars from 2001 and 2002 were excluded because the data was in an old Excel file format which I couldn't open.

The data was sales-weighted by *year*.  Total car sales by year is at 

    http://www.statista.com/statistics/199974/us-car-sales-since-1951/

The data was *not* sales-weighted by *model*, because I couldn't figure out how to find and join that data.  So we're assuming that there are just as many Aston Martins as Honda Civics.  Hopefully it will come out in the wash.


For "MPG distribution for new cars on sale (in 2008)", I used the data just from year 2008.  Again, not sales-weighted by model, just one tick per available model.




================================================
FILE: README.md
================================================
What can a technologist do about climate change? A personal view.
http://worrydream.com/ClimateChange/


================================================
FILE: Script/autocomplete-video.js
================================================
//
//  autocomplete-video.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//


(function(){

var setupAutocompleteVideo = this.setupAutocompleteVideo = function () {
    var div = document.querySelector(".autocomplete-video");
    var video = div.querySelector("video");
    prepareVideo(video, div);
}


function prepareVideo (video, div) {
    var ua = navigator.userAgent.toLowerCase();
    var noPlayButton = ua.match(/iphone/) || ua.match(/ipod/);

    var width = parseInt(video.getAttribute("width"));
    var height = parseInt(video.getAttribute("height"));
    
    var chrome = div.querySelector(".videoChrome");

    var videoOverlay = chrome.querySelector(".videoOverlay");
    var videoPlayButton = chrome.querySelector(".videoPlayButton");
    var videoDarken = chrome.querySelector(".videoDarken");
    var marker = chrome.querySelector(".marker");
    var markerProgressCanvas = chrome.querySelector(".markerProgressCanvas");
    var markerProgressOverlay = chrome.querySelector(".markerProgressOverlay");
    var markerPlayAgain = chrome.querySelector(".markerPlayAgain");
    
    var insetTop = parseInt(div.getAttribute("data-top") || "0");
    var insetBottom = parseInt(div.getAttribute("data-bottom") || "0");
    var insetRight = parseInt(div.getAttribute("data-right") || "0");
    var insetRightPost = parseInt(div.getAttribute("data-postright") || insetRight.toString());
    var insetLeft = parseInt(div.getAttribute("data-left") || "0");
    var pushLeft = parseInt(div.getAttribute("data-push-left") || "0");
    var verboseButton = parseInt(div.getAttribute("data-verbose-button") || "0");
    var noMarker = parseInt(div.getAttribute("data-no-marker") || "0");

    height -= insetTop + insetBottom;
    width -= insetLeft + insetRight + pushLeft;

    chrome.style.display = "block";

    if (verboseButton) { addClass(videoPlayButton, "verbose"); } 
    else { removeClass(videoPlayButton, "verbose"); }
    
    if (noPlayButton) { videoPlayButton.style.display = "none"; }
    if (noMarker) { marker.setStyle.display = "none"; }


    // sizes
    
    var updateSizes = function () {
        div.style.left = -pushLeft + "px";
        chrome.style.width = width + "px";
        chrome.style.height = height + "px";
        chrome.style.top = insetTop + "px";
        chrome.style.left = pushLeft + "px";
        videoOverlay.style.width = (width - 2) + "px";
        videoOverlay.style.height = (height - 2) + "px";
        videoOverlay.style.left  = insetLeft + "px";
        
        videoDarken.style.left = insetLeft + "px";
        videoPlayButton.style.left = Math.round(0.5 * (width - 78)) + "px";
        videoPlayButton.style.top = Math.round(0.5 * (height - (verboseButton ? 88 : 78))) + "px";
    };

    updateSizes();
    

    // playing

    var isPlaying = false;
    var didPlay = false;
    
    var playVideo = function () {
        isPlaying = true;
        didPlay = true;

        videoOverlay.style.display = "none";
        videoDarken.style.backgroundColor = "transparent";
        videoDarken.style.cursor = "none";

        markerProgressCanvas.style.display = "block";
        markerProgressOverlay.style.display = "block";
        markerPlayAgain.style.display = "none";
        
        width += insetRight - insetRightPost;
        insetRight = insetRightPost;
        updateSizes();
        
        updateCurrentTime();
        video.play();
    };
    
    var videoWasClicked = function () {
        if (isPlaying && !video.paused) {
            video.setAttribute("controls", "controls");
            videoDarken.style.display = "none";
            video.pause();
        }
        else {
            video.removeAttribute("controls");
            videoDarken.style.display = "block";
            playVideo();
        }
    };
    
    var updateCurrentTime = function () {
        var duration = video.duration;
        if (isNaN(duration) || duration <= 0) { return; }
        var currentTime = video.currentTime;
        if (isNaN(currentTime)) { currentTarget = 0; }
        
        updateCanvasWithProgress(markerProgressCanvas, currentTime / duration);
    };


    // video events

    video.addEventListener("timeupdate", function () {
        updateCurrentTime();
    }, false);
    
    video.addEventListener("ended", function () {
        isPlaying = false;
        
        videoDarken.style.cursor = "pointer";
        markerProgressCanvas.style.display = "none";
        markerProgressOverlay.style.display = "none";
        markerPlayAgain.style.display = "block";

    }, false);
    

    // marker mousing

    marker.addEventListener("click", function () {
        videoWasClicked();
    });


    // video mousing
    // (events added to videoDarken because iPad can't deal with click event on video element itself)
   
    videoDarken.addEventListener("click", function () {
        videoWasClicked();
    });

    videoDarken.addEventListener("mouseenter", function () {
        if (isPlaying) { return; }

        if (didPlay) {
            videoOverlay.style.display = "block";
        }
        else {
            videoDarken.style.backgroundColor = "rgba(0,0,0,0.1)";
        }
    });
    
    videoDarken.addEventListener("mouseleave", function () {
        if (isPlaying) { return; }

        if (didPlay) {
            videoOverlay.style.display = "none";
        }
        videoDarken.style.backgroundColor = "transparent";
    });
}


function updateCanvasWithProgress (canvas, progress) {
    var width = parseInt(canvas.getAttribute("width"));
    var height = parseInt(canvas.getAttribute("height"));
    var ctx = canvas.getContext("2d");
    
    ctx.clearRect(0,0,width,height);
    ctx.save();
    ctx.translate(width/2, height/2);
    
    var radius = width/2 - 1;

    ctx.beginPath();
    ctx.arc(0,0, radius, -Math.PI * 0.5, -Math.PI * 0.5 + progress * Math.PI * 2);
    ctx.lineTo(0,0);
    ctx.lineTo(0, radius);
    ctx.fillStyle = "rgba(0,0,0,0.2)";
    ctx.fill();
    
    ctx.restore();
}


//====================================================================================

})();



================================================
FILE: Script/carbon-budget.js
================================================
//
//  carbon-budget.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//

(function () {

var carbonBudgetTangle;

var x0 = 286, y0 = 176.5;
var x1 = 432, y1 = 18.5;
var A = (327.8 - x0) * (y0 - (18.5 + 13.3)/2);

var h1 = y0 - y1;

var setupCarbonBudget = this.setupCarbonBudget = function () {
    var root = document.getElementById("carbon-budget-figure");
    carbonBudgetTangle = new Tangle(root, {
        initialize: function () {
            this.knobPoint = [ x1, 0 ];
        },
        update: function () {
            var budgetArea = document.getElementById("carbon-budget-future-budget");
            var overdrawnArea = document.getElementById("carbon-budget-future-overdrawn");
            if (!budgetArea || !overdrawnArea) { return; }
        
            var p = getInterceptionPoint(this.knobPoint);
            
            var budgetPath = sprintf("M286,18.5L%.1f,%.1fV176.5H286Z", p[0], p[1]);
            var overdrawnPath = sprintf("M%.1f,%.1fL%.1f,%.1fV176.5H%.1fZ", p[0], p[1], this.knobPoint[0], this.knobPoint[1], p[0]);
            
            budgetArea.setAttribute("d", budgetPath);
            overdrawnArea.setAttribute("d", overdrawnPath);
        }
    });
}

function getInterceptionPoint (knobPoint) {
    var h2 = y0 - knobPoint[1];
    var w = knobPoint[0] - x0;
    
    // If I could put a diagram here, I could explain how this works.
    // But this is a "text file".  So no explanation for you.

    var w1 = (h1 - Math.sqrt(h1*h1 - 2*A*(h1-h2) / w)) / ((h1-h2)/w);
    if (Math.abs(h1-h2) < 1e-5) { w1 = A/h1; }
    var hh = h1 - (w1/w)*(h1-h2);
    
    if (isNaN(w1)) { return [ knobPoint[0], knobPoint[1] ]; }

    return [ x0 + w1, y0 - hh ];
}


Tangle.classes["carbon-budget-knob"] = {

    initialize: function (element, options, tangle, variable) {
        this.element = element;
        this.tangle = tangle;
        this.variable = variable;
        
        this.helpElement = this.element.parentNode.querySelector(".carbon-budget-knob-help");
        
        this.initializeHover();
        this.initializeDrag();
    },

    update: function (element, value) {
        element.style.left = value[0] + "px";
        element.style.top = value[1] + "px";
    },
    
    // hover
    
    initializeHover: function () {
        this.isHovering = false;
        this.element.addEventListener("mouseenter", (function () { this.setHovering(true) }).bind(this));
        this.element.addEventListener("mouseleave", (function () { this.setHovering(false) }).bind(this));
    },
    
    setHovering: function (hovering) {
        this.isHovering = hovering;
        this.updateRolloverEffects();
    },
    
    updateRolloverEffects: function () {
        this.updateStyle();
        this.updateCursor();
    },
    
    isActive: function () {
        return this.isDragging || this.isHovering;
    },

    updateStyle: function () {
        var figure = ancestorWithClass(this.element, "figure");
        if (this.isDragging) { 
            addClass(this.element, "dragging");
            if (figure) { addClass(figure, "hold-cite"); }
        }
        else {
            removeClass(this.element, "dragging");
            if (figure) { removeClass(figure, "hold-cite"); }
        }
    },

    updateCursor: function () {
        var body = document.body;
        if (this.isActive()) { addClass(body,"TKCursorDrag"); }
        else { removeClass(body,"TKCursorDrag"); }
    },


    // drag
    
    initializeDrag: function () {
        this.isDragging = false;
        makeTouchable(this.element, this);
    },
    
    touchDown: function (e,x,y) {
        isAnyAdjustableNumberDragging = true;
        this.isDragging = true;
        this.valueAtMouseDown = this.tangle.getValue(this.variable);
        this.pointAtMouseDown = [x,y];

        this.updateRolloverEffects(true);
        this.updateStyle();

        if (this.helpElement) { 
            this.helpElement.style.display = "none"; 
            this.helpElement = undefined;
        }
    },
    
    touchMove: function (e,x,y) {
        var delta = [ x - this.pointAtMouseDown[0], y - this.pointAtMouseDown[1] ];
        var unclippedValue = [ this.valueAtMouseDown[0] + delta[0], this.valueAtMouseDown[1] + delta[1] ];
        
        var isRightEdge = Math.abs(unclippedValue[0] - x1) < Math.abs(unclippedValue[1] - y0);
        var value = isRightEdge ? [ x1, clip(unclippedValue[1], 0, y0) ] : [ clip(unclippedValue[0], x0 + 20, x1), y0 ];
        
        this.tangle.setValue(this.variable, value);
    },
    
    touchUp: function (e) {
        this.isDragging = false;

        this.updateRolloverEffects();
        this.updateStyle();
    }
};

function clip (x,min,max) { return x < min ? min : x > max ? max : x; }

})();


================================================
FILE: Script/chart-data.js
================================================
var chart_data = {};

chart_data["01-private-late"] = {
    title:"late-stage venture capital funding in cleantech",
    href:"Notes/01-private.txt",
    source:"PricewaterhouseCoopers Cleantech MoneyTree Report",
    format: function (x) { return sprintf("$%.1f B", x/1000); },
    labelWidth: 66,
    topValue:3806.5 - 890.0,
    bars: [
        ["2009", 2481.8 - 619.2 ],
        ["2010", 3806.5 - 890.0 ],
        ["2011", 4278.2 - 1386.6 ],
        ["2012", 2754.3 - 574.8 ],
        ["2013", 1379.9 - 252.9 ],
        ["2014", 1980.1 - 142.3 ],
    ],
};

chart_data["01-private-early"] = {
    title:"early-stage venture capital funding in cleantech",
    href:"Notes/01-private.txt",
    source:"PricewaterhouseCoopers Cleantech MoneyTree Report",
    format: function (x) { return sprintf("$%.1f B", x/1000); },
    labelWidth: 66,
    topValue:3806.5 - 890.0,
    bars: [
        ["2009", 619.2  ],
        ["2010", 890.0  ],
        ["2011", 1386.6,  { "annotation":"(peak)" } ],
        ["2012", 574.8,  { "annotation":"(crash)" } ],
        ["2013", 252.9  ],
        ["2014", 142.3, { "annotation":"(all but disappeared)" } ],
    ],
};

chart_data["02-pollutants"] = {
    title:"contribution to global warming from things dumped into the sky",
    href:"Notes/02-pollutants.jpg",
    source:"Al Gore. Our Choice, p 47",
    format: "%d%%",
    topValue: 87,
    labelWidth: 124,
    bars: [
        [ "carbon dioxide (CO2)", 43 ],
        [ "methane (CH4)", 27 ],
        [ "black carbon (soot)", 12 ],
        [ "halocarbons", 8 ],
        [ "CO and VOCs", 7 ],
        [ "nitrous oxide (N2O)",  4 ],
    ],
};

chart_data["02-sources"] = {
    title:"human sources of carbon dioxide",
    href:"http://whatsyourimpact.org/greenhouse-gases/carbon-dioxide-sources",
    format: "%d%%",
    topValue: 87,
    labelWidth: 124,
    bars: [
        [ "burning fossil fuels", 87 ],
        [ "land use changes", 9, { "annotation":"(primarily deforestation, primarily for agriculture)" } ],
        [ "industrial processes",  4 ],
    ],
};

chart_data["02-solar-land"] = {
    title:"percent of land in continental U.S.",
    href:"Notes/02-solar-land.txt",
    format: function (x) { return sprintf("%.1f%%", (x / 2300000) * 100); },
    labelWidth: 240,
    bars: [
        [ "land devoted to agriculture", 1173000 ],
        [ "land required for solar to provide all U.S. energy", 53400, ],
        [ "land required for solar to provide U.S. electricity", 17300, 
            { "annotation":"(excluding cars, heating, etc.)" } ],
        [ "land devoted to roads", 17929 ],
    ],
};

chart_data["02-solarcost"] = {
    title:"breakdown of solar cost per watt, 2014-2017 (projected)",
    href:"http://www.qualenergia.it/sites/default/files/articolo-doc/Solar%202015%20Outlook(1).pdf",
    comment:"figure 26: cost reduction example",
    format: function (x) { return sprintf("$%.2f", x / 100); },
    topValue: 290,
    labelWidth: 58,
    lineHeight: 14,
    labels: [ "panel", "inverter", "rack", "BoS", "installation", "sales", "other" ],
    chart:"stacked",
    bars: [
        [ "2014", [ 75, 25, 25, 30, 65, 50, 20 ] ],
        [ "2015", [ 70, 23, 23, 25, 60, 47, 18 ] ],
        [ "2016", [ 65, 20, 19, 20, 45, 30, 16 ] ],
        [ "2017", [ 50, 17, 16, 17, 45, 20, 12 ] ],
    ]
};


var transportationPixelsPerValue = 0.017;

chart_data["04-sectors"] = {
    title:"U.S. energy consumption, 2014",
    page:"https://flowcharts.llnl.gov",
    href:"https://flowcharts.llnl.gov/content/assets/images/energy/us/Energy_US_2014.png",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(Math.round(100*x/sum))); },
    pixelsPerValue: transportationPixelsPerValue,
    labelWidth: 94,
    bars: [
        [ "transportation", 27100, { "class":"transportation" } ],
        [ "manufacturing", 24700, { "class":"manufacturing" } ],
        [ "residential", 11800, { "class":"residential" } ],
        [ "commercial", 8930, { "class":"commercial" } ],
    ],
};

chart_data["04-residential"] = {
    title:"residential breakdown",
    icon:'<img style="margin-right:1px;" src="Images/04-icon-residential.svg" width="20" height="20">',
    href:"http://www.eia.gov/consumption/residential/data/2009/index.cfm?view=consumption",
    page:"http://www.eia.gov/consumption/data.cfm#rec",
    comment:"CE3.1",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    pixelsPerValue: transportationPixelsPerValue,
    scaleToSum: 11800,
    labelWidth: 94,
    rectClass: "residential",
    bars: [
        [ "space heating", 4226 ],
        [ "water heating", 1803 ],
        [ "air conditioning", 635 ],
        [ "refrigerators", 484 ],
        [ "other", 3035 ],
    ],
};

chart_data["04-commercial"] = {
    title:'commercial breakdown',
    icon:'<img style="margin-left:-7px;margin-right:2px;" src="Images/04-icon-commercial.svg" width="20" height="20">',
    href:"http://www.eia.gov/consumption/commercial/data/2003/pdf/e01a.pdf",
    page:"http://www.eia.gov/consumption/data.cfm#cec",
    comment:"Table E1A",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    pixelsPerValue: transportationPixelsPerValue,
    scaleToSum: 8930,
    labelWidth: 94,
    rectClass: "commercial",
    bars: [
        [ "space heating", 2365 ],
        [ "lighting", 1340 ],
        [ "cooling", 516 ],
        [ "water heating", 501 ],
        [ "ventilation", 436 ],
        [ "refrigeration", 381 ],
        [ "cooking", 190 ],
        [ "computers", 156 ],
        [ "office equipment", 69 ],
        [ "other", 569 ],
    ],
};

chart_data["04-manufacturing"] = {
    title:'manufacturing breakdown',
    icon:'<img src="Images/04-icon-manufacturing.svg" width="20" height="20">',
    page:"http://www.eia.gov/consumption/data.cfm#mfg",
    href:"http://www.eia.gov/consumption/manufacturing/data/2010/pdf/Table1_1.pdf",
    comment:"Table 1_1",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    pixelsPerValue: transportationPixelsPerValue,
    scaleToSum: 24700,
    labelWidth: 154,
    rectClass: "manufacturing",
    bars: [
        [ "petroleum and coal products", 6137 ],
        [ "chemicals", 4995 ],
        [ "paper", 2109 ],
        [ "primary metals", 1608 ],
        [ "food", 1162 ],
        [ "nonmetallic mineral products", 716 ],
        [ "wood products", 473 ],
        [ "fabricated metal products", 302 ],
        [ "transportation equipment", 279 ],
        [ "plastics and rubber products", 275 ],
        [ "other", 760 ],
    ],
};

chart_data["04-transportation"] = {
    title:'transportation breakdown',
    icon:'<img style="margin-top:-5px; margin-right:4px;" src="Images/04-icon-transportation.svg" width="25" height="25">',
    page:"http://cta.ornl.gov/data/chapter2.shtml",
    href:"http://cta.ornl.gov/data/tedb34/Spreadsheets/Table2_08.xls",
    comment:"Table 2.8 Transportation Energy Use by Mode, 2012–2013",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    pixelsPerValue: transportationPixelsPerValue,
    scaleToSum: 27100,
    labelWidth: 84,
    rectClass: "transportation",
    bars: [
        [ "cars", 7046.6 ],
        [ "light trucks", 8076.9 ],
        [ "heavy trucks", 5923.8 ],
        [ "air", 2037 ],
        [ "water", 1054.9 ],
        [ "rail", 610.8 ],
        [ "pipeline", 1140.8 ],
    ],
};


chart_data["04-transportation-CO2"] = {
    title:"transportation-related CO<sub>2</sub> emissions in U.S., 2013",
    href:"http://cta.ornl.gov/data/tedb34/Edition34_Chapter11.pdf",
    comment:"table 11.8: Transportation Carbon Dioxide Emissions by Mode, 1990–2013",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    topValue: 1032,
    labelWidth: 114,
    bars: [
        [ "passenger vehicles", 1032 ],
        [ "heavy trucks", 410.8 ],
        [ "air", 148.6 ],
        [ "rail", 44.4 ],
        [ "water", 38.8 ],
        [ "pipeline",  47.7 ],
    ],
};

chart_data["04-ev-grid"] = {
    title:"well-to-wheels greenhouse gas emissions per vehicle, in CO<sub>2</sub>-equiv tons per year",
    href: "http://www.afdc.energy.gov/vehicles/electric_emissions.php",
    format: "%.1f",
    labelWidth: 154,
    bars: [
        [ "gasoline car", 14815 / 2000 ],
        [ "electric car in Illinois", 9074 / 2000 ],
        [ "electric car, U.S. average", 7657 / 2000 ],
        [ "electric car in California", 4152 / 2000 ],
        [ "electric car in New York", 3431 / 2000 ],
        [ "electric car, 100% renewables", 0 ],
    ],
};

chart_data["04-trip-distribution"] = {
    title:"distribution of U.S. car trips",
    href: "http://www.solarjourneyusa.com/EVdistanceAnalysis7.php",
    format: " ",
    labelWidth: 40,
    lineHeight: 3,
    barHeight: 2,
    barYOffset: 7,
    fullHeight: 180,
    bars: [
        [ " 0 miles", 208 ],
        [ "", 241 ],
        [ "", 266 ],
        [ "", 215 ],
        [ "", 157 ],
        [ "", 157 ],
        [ "", 104 ],
        [ "", 90  ],
        [ "", 79  ],
        [ "", 45  ],
        [ "10 miles", 83  ],
        [ "", 30  ],
        [ "", 52  ],
        [ "", 27  ],
        [ "", 24  ],
        [ "", 56  ],
        [ "", 19  ],
        [ "", 20  ],
        [ "", 21  ],
        [ "", 9   ],
        [ "20 miles", 34  ],
        [ "", 10  ],
        [ "", 12  ],
        [ "", 10  ],
        [ "", 8   ],
        [ "", 22  ],
        [ "", 8   ],
        [ "", 7   ],
        [ "", 7   ],
        [ "", 4   ],
        [ "30 miles", 17  ],
        [ "", 3   ],
        [ "", 6   ],
        [ "", 4   ],
        [ "", 4   ],
        [ "", 10  ],
        [ "", 4   ],
        [ "", 3   ],
        [ "", 3   ],
        [ "", 1   ],
        [ "40 miles", 8   ],
        [ "", 1   ],
        [ "", 3   ],
        [ "", 2   ],
        [ "", 0   ],
        [ "", 6   ],
        [ "", 0   ],
        [ "", 1   ],
        [ "", 0   ],
        [ "", 0   ],
        [ "50 miles", 6   ],
    ],
};

chart_data["04-truck-emissions"] = {
    title:"long-haul truck emissions in ten years, under different tech adoption scenarios",
    href: "http://www.grahampeacedesignmail.com/cwr/cwr2012_trucking_finall_download_singles.pdf",
    source: "Road Transport: Unlocking Fuel-Saving Technologies In Trucking And Fleets, Nov 2012, figure 5",
    format: function (x) { return sprintf("%d%%", Math.round(100*x)); },
    labelWidth: 126,
    bars: [
        [ "business as usual", 394698 / 306034 ],  //  ktons CO2, 2021 value / 2011 value
        [ "base tech adoption", 370619 / 306034 ],
        [ "aggressive adoption", 359817 / 306034 ],
        [ "complete adoption", 310084 / 306034 ],
        [ "and better logistics", 274304 / 306034 ],
    ],
};

chart_data["04-residential-electricity"] = {
    title:"residential electricity consumption in U.S.",
    href: "http://www.eia.gov/tools/faqs/faq.cfm?id=96&t=3",
    format: function (x,i,sum) { return sprintf("%d%%", Math.round(100*x/sum)); },
    labelWidth: 98,
    bars: [
        [ "space cooling", 0.64 ],
        [ "lighting", 0.51 ],
        [ "water heating", 0.45 ],
        [ "space heating", 0.45 ],
        [ "refrigeration", 0.36 ],
        [ "television etc", 0.33 ],
        [ "clothes dryers", 0.20 ],
        [ "furnace fans etc", 0.15 ],
        [ "other", 1.74 ],
    ],
};

chart_data["04-per-capita"] = {
    title: "per capita electricity use in MWh",
    href: "http://www.arb.ca.gov/research/seminars/chu/chu.pdf",
    lines: [
        { label:"California",
          units: "kWh",
          values: [ 3632, 3754, 3799, 3920, 4238, 4435, 4813, 5040, 5388, 5645, 5933, 6175, 6554, 6690, 6190, 6886, 7098, 7083, 7098, 7280, 7008, 7144, 6826, 6796, 7174, 7280, 7114, 7295, 7477, 7522, 7613, 7265, 7310, 7250, 7295, 7280, 7492, 7613, 7431, 7568, 7719, 7280 ],
        },
        { label:"U.S.",
          units: "kWh",
          values: [3814, 3935, 4177, 4419, 4677, 4919, 5282, 5555, 6024, 6508, 6826, 7098, 7598, 8082, 7976, 8082, 8521, 8854, 9066, 9202, 9232, 9338, 8990, 9187, 9671, 9762, 9853, 10125, 10534, 10701, 10897, 10943, 10822, 11094, 11261, 11457, 11669, 11715, 11972, 12123, 12411, 12214],
        },
    ],
    domain: [ 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 ],
};




================================================
FILE: Script/charts.js
================================================
//
//  charts.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//

var svgns = "http://www.w3.org/2000/svg";

function placeChart(div, name) {
    var data = chart_data[name];
    
    var figure = div;

    var titleHTML = (data.icon ? data.icon + " " : "") + data.title;
    titleHTML += ' <span class="cite">' + 
                  getHTMLForCitation("source", data.href) +
                  getHTMLForCitation("data", "data.html?id=" + name) +
                 '</span>';
    var title = createElement("div", { "class":"figure-caption" + (data.icon ? " with-icon" : ""), "html":titleHTML });
    figure.appendChild(title);

    var svg = document.createElementNS(svgns, "svg");
    svg.setAttribute("class", "chart");
    figure.appendChild(svg);
    
    if (!data.chart) { 
        drawBarChart(svg,data);
    }
    else if (data.chart === "stacked") {
        drawStackedBars(svg,data);
    }
    else {
        console.log("unknown chart type", data.chart);
    }
}

function getHTMLForCitation(what, href) {
    if (!href) { return ""; }
    return '<a href="' + href + '">(' + what + ')</a>';
}


// draw

function drawBarChart (svg,data) {
    var sum = data.bars.reduce(function (acc,bar) { return acc + bar[1]; }, 0);
    var max = data.bars.reduce(function (acc,bar) { return Math.max(acc, bar[1]); }, 0);
    
    var topValue = data.topValue || max;
    var fullWidth = data.fullWidth || 440;
    var labelWidth = data.labelWidth || 120;
    var barHeight = data.barHeight || 6;
    var barYOffset = data.barYOffset || 4;
    var lineHeight = data.lineHeight || 13;
    var format = data.format || "%d";
    var scale = data.scaleToSum ? (data.scaleToSum / sum) : 1;
    
    if (data.pixelsPerValue) {
        fullWidth = labelWidth + Math.ceil(data.pixelsPerValue * max * scale) + 5;
    }

    var barWidth = fullWidth - labelWidth;
    var fullHeight = data.fullHeight || (data.bars.length * lineHeight);
    
    var x = function (a) { return remap(a, 0, topValue, 0, barWidth); };
    
    svg.setAttributeNS(null, "width", fullWidth);
    svg.setAttributeNS(null, "height", fullHeight);
    
    data.bars.forEach(function (d, i) {
        var g = document.createElementNS(svgns, "g");
        g.setAttributeNS(null, "transform", "translate(0," + (i * lineHeight) + ")");
        
        var rect = document.createElementNS(svgns, "rect");
        rect.setAttributeNS(null, "class", (d[2] && d[2].class) || data.rectClass || "" );
        rect.setAttributeNS(null, "x", labelWidth);
        rect.setAttributeNS(null, "y", barYOffset);
        rect.setAttributeNS(null, "width", x(d[1]));
        rect.setAttributeNS(null, "height", barHeight);
        g.appendChild(rect);

        var label = document.createElementNS(svgns, "text");
        label.setAttributeNS(null, "class", "label");
        label.setAttributeNS(null, "x", 0);
        label.setAttributeNS(null, "y", 0);
        label.setAttributeNS(null, "dy", "1em");
        label.appendChild(document.createTextNode(d[0]));
        g.appendChild(label);
        
        var amount = document.createElementNS(svgns, "text");
        amount.setAttributeNS(null, "class", "amount");
        amount.setAttributeNS(null, "x", labelWidth - 5);
        amount.setAttributeNS(null, "y", 0);
        amount.setAttributeNS(null, "dy", "1em");
        amount.appendChild(document.createTextNode(
            typeof(format) == "function" ? format(d[1]*scale, i, sum*scale) : sprintf(format, d[1]*scale)));
        g.appendChild(amount);
        
        if (d[2] && d[2].annotation) {
            var annotation = document.createElementNS(svgns, "text");                                         
            annotation.setAttributeNS(null, "class", "annotation")
            annotation.setAttributeNS(null, "x", labelWidth + x(d[1] * scale) + 5);
            annotation.setAttributeNS(null, "y", 0);
            annotation.setAttributeNS(null, "dy", "1em");
            annotation.appendChild(document.createTextNode(d[2].annotation));
            g.appendChild(annotation);
        }             

        svg.appendChild(g);
    });
}

function drawStackedBars (svg,data) {
    var fullWidth = data.fullWidth || 440;
    var labelWidth = data.labelWidth || 120;
    var lineHeight = data.lineHeight || 13;
    var captionHeight = 13;
    var format = data.format || "%d";

    var barWidth = fullWidth - labelWidth;
    var fullHeight = captionHeight + data.bars.length * lineHeight;
    
    var x = function (a) { return remap(a, 0, data.topValue, 0, barWidth); };
    
    svg.setAttributeNS(null, "width", fullWidth);
    svg.setAttributeNS(null, "height", fullHeight);

    data.bars.forEach(function (bar) {
        var cumsum = 0;
        bar.segments = bar[1].map(function (n,i) {
            var segment = { left:cumsum, width:n };
            cumsum += n;
            return segment;
        });
        bar.sum = cumsum;
    });

    var labeldata = data.labels.map(function (label, i) {
        return { label:label, segment:data.bars[0].segments[i] };
    });
    
    
    // captions
    
    var captions = document.createElementNS(svgns, "g");
    captions.setAttributeNS(null, "transform", "translate(" + labelWidth + ",0)");
    
    labeldata.forEach(function (d,i) {
        var caption = document.createElementNS(svgns, "text");
        caption.setAttributeNS(null, "class", "label stack-caption")
        caption.setAttributeNS(null, "x", x(d.segment.left + 0.5 * d.segment.width));
        caption.setAttributeNS(null, "y", captionHeight - 1);
        caption.appendChild(document.createTextNode(d.label));
        captions.appendChild(caption);
    });

    svg.appendChild(captions);
        
        
    // bars

    data.bars.forEach(function (d, i) {
        var g = document.createElementNS(svgns, "g");
        g.setAttributeNS(null, "transform", "translate(0," +  (captionHeight + i * lineHeight) + ")");

        var label = document.createElementNS(svgns, "text");
        label.setAttributeNS(null, "class", "label");
        label.setAttributeNS(null, "x", 0);
        label.setAttributeNS(null, "y", 0);
        label.setAttributeNS(null, "dy", "1em");
        label.appendChild(document.createTextNode(d[0]));
        g.appendChild(label);

        var amount = document.createElementNS(svgns, "text");
        amount.setAttributeNS(null, "class", "amount");
        amount.setAttributeNS(null, "x", labelWidth - 5);
        amount.setAttributeNS(null, "y", 0);
        amount.setAttributeNS(null, "dy", "1em");
        amount.appendChild(document.createTextNode(
            typeof(format) == "function" ? format(d.sum) : sprintf(format, d.sum)));
        g.appendChild(amount);
              
        var stack = document.createElementNS(svgns, "g");
        stack.setAttributeNS(null, "transform", "translate(" + labelWidth + ",0)");
        
        d.segments.forEach(function (d,i) {
            var rect = document.createElementNS(svgns, "rect");
            rect.setAttributeNS(null, "class", "segment" + i);
            rect.setAttributeNS(null, "x", x(d.left));
            rect.setAttributeNS(null, "y", 4);
            rect.setAttributeNS(null, "width", x(d.width) - 2);
            rect.setAttributeNS(null, "height", 6);
            stack.appendChild(rect);
        });
        
        g.appendChild(stack);
        svg.appendChild(g);
    });
}


================================================
FILE: Script/clunker.js
================================================
//
//  clunker.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//

(function () {

var clunkerTangle;
var clunkerCalculationDivs = {};

//--------------------------------------------------------------------------------
//
//  calculations for each calculated variable
//
//  These are both eval'd and turned into HTML for display

var clunkerModels = [
    {
        name:"cars_traded",
        lines: [
            "this.budget = params.budget",
            "this.rebate = params.rebate",
            "this.overhead = params.overhead",

            { spacer:2, },
            { comment:"Assume that the program “sells out”, and all available rebates are collected.  Given the demand for new cars, this will be true for any reasonable rebate amount." },
            { spacer:1 },
            "this.cars_traded = ( this.budget - this.overhead ) / this.rebate",
        ],
    },
    {
        name:"gallons_saved",
        lines: [
            "this.old_MPG_limit = params.old_MPG_limit",
            "this.old_MPGs = params.old_MPGs",
            { spacer:1 },
            "this.eligible_old_MPGs = select this.old_MPGs where mpg < this.old_MPG_limit",
            
            { spacer:2 },
            { comment:"Assume that traded-in cars are chosen with equal probability from the pool of eligible cars.  We use the harmonic average because we'll be calculating gallons consumed for constant miles, so we really want to be averaging gallons-per-mile." },
            { spacer:1 },
            "this.average_old_MPG = harmonic-average this.eligible_old_MPGs",
            
            { separator:1 },
            
            "this.new_MPG_limit = params.new_MPG_limit",
            "this.new_MPGs = params.new_MPGs",
            { spacer:1 },
            "this.eligible_new_MPGs = select this.new_MPGs where mpg > this.new_MPG_limit",
            
            { spacer:2 },
            { comment:"Assume that new cars are purchased with equal probability from the pool of eligible cars.  The distribution really should be sales-weighted.  I'm sure the data is available, but I couldn't find it." },
            { spacer:1 },
            "this.average_new_MPG = harmonic-average this.eligible_new_MPGs",
            
            { separator:1 },
            
            { comment:"Assume that everyone who is buying a new car now would have eventually bought a similar car when their current car got too old.  So the fuel savings from the program should be calculated over the remaining lifetime of the old car.  Ideally we'd like the joint distribution of MPGs and age of the current fleet, but I can't find that data.  So we'll just use averages.",
              style:"margin-bottom:10px;" },
            
            "this.car_lifetime_miles = params.car_lifetime_miles",
            "this.average_miles_left = params.fraction_lifetime_left * this.car_lifetime_miles",
            { spacer:1 },
            "this.gallons_used_by_old_car = this.average_miles_left / this.average_old_MPG",
            "this.gallons_used_by_new_car = this.average_miles_left / this.average_new_MPG",
            "this.gallons_saved_per_car = this.gallons_used_by_old_car - this.gallons_used_by_new_car",

            { separator:1 },
            
            "this.cars_traded = params.cars_traded",
            "this.gallons_saved = this.gallons_saved_per_car * this.cars_traded",
        ],
    },
    {
        name:"hours_of_gas",
        lines: [
            "this.gallons_saved = params.gallons_saved",
            { spacer:1 },
            "this.gallons_consumed_per_day = params.gallons_consumed_per_day",
            "this.gallons_consumed_per_hour = this.gallons_consumed_per_day / params.hours_per_day",
            { spacer:1 },
            "this.hours_of_gas = this.gallons_saved / this.gallons_consumed_per_hour",
        ],
    },
    {
        name:"tons_CO2e_saved",
        lines: [
            "this.gallons_saved = params.gallons_saved",
            { spacer:1 },
            "this.kg_CO2_per_gallon_gas = params.kg_CO2_per_gallon_gas",
            "this.tons_CO2_saved = this.gallons_saved * this.kg_CO2_per_gallon_gas / params.kg_per_ton",
            { spacer:2, },
            { comment:"CO<sub>2</sub> comprises 95% of a car's greenhouse gas emissions.  The other 5% include methane, nitrous oxide, and hydroflourocarbons.  To account for these other gases, we divide the amount of CO<sub>2</sub> by 0.95 to get CO<sub>2</sub>e (“carbon dioxide equivalent”)." },
            { spacer:1 },
            "this.CO2_per_CO2e = params.CO2_per_CO2e",
            "this.tons_CO2e_saved = this.tons_CO2_saved / this.CO2_per_CO2e",
        ],
    },
    {
        name:"percent_annual_emissions",
        lines: [
            "this.tons_CO2e_saved = params.tons_CO2e_saved",
            "this.tons_CO2e_emitted_yearly = params.tons_CO2e_emitted_yearly",
            { spacer:1 },
            "this.percent_annual_emissions = this.tons_CO2e_saved / this.tons_CO2e_emitted_yearly * params.units_per_percent",
        ],
    },
    {
        name:"dollars_per_ton_CO2e",
        lines: [
            "this.budget = params.budget",
            "this.tons_CO2e_saved = params.tons_CO2e_saved",
            { spacer:1 },
            "this.dollars_per_ton_CO2e = this.budget / this.tons_CO2e_saved",
        ],
    },
    {
        name:"dollars_per_ton_CO2e_on_balance",
        lines: [
            "this.gallons_saved = params.gallons_saved",
            "this.dollars_per_gallon = params.dollars_per_gallon",
            "this.dollars_saved_buying_less_gas = this.gallons_saved * this.dollars_per_gallon",
            { spacer:1 },
            "this.budget = params.budget",
            "this.dollars_spent_on_balance = this.budget - this.dollars_saved_buying_less_gas",
            { spacer:1 },
            "this.tons_CO2e_saved = params.tons_CO2e_saved",
            "this.dollars_per_ton_CO2e_on_balance = this.dollars_spent_on_balance / this.tons_CO2e_saved",
        ],
    },
];


//--------------------------------------------------------------------------------
//
//  variable metadata

var clunkerVariables = {
    "budget": { value:3e9, min:0.1e9, max:20e9, step:0.1e9, fmt:function (v) { return sprintf("$%.1f billion", v * 1e-9); } },
    "rebate": { value:3500, min:1000, max:10000, step:100, fmt:function (v) { return "$" + commas(v); } },
    "overhead": { value:100e6, min:0, max:10e9, step:10e6, fmt:function (v) { return "$" + commas(v * 1e-6) + " million"; } },
    "cars_traded": { fmt:function (v) { return commas(v); } },
    
    "old_MPG_limit": { value:17, min:10, max:45, step:1, fmt:function (v) { return sprintf("%d MPG", v); } },
    "old_MPGs": { value:createDistribution([ 0, 0, 0, 0, 0, 0, 0, 0, 85, 355, 493, 1270, 3114, 4037, 6636, 8932, 10051, 9932, 10309, 12924, 18508, 14603, 13452, 14563, 11454, 9715, 8032, 7045, 5841, 4835, 3633, 3225, 2642, 1624, 1427, 910, 671, 510, 590, 837, 426, 334, 237, 157, 110, 207, 312, ]),
                  className:"distribution", comment:"miles-per-gallon distribution for cars currently on the road",
                  href:"Notes/06-clunker.txt" },
    "eligible_old_MPGs": { className:"distribution", comment:"miles-per-gallon distribution for cars eligible for trade-in" },
    "average_old_MPG": { fmt:function (v) { return sprintf("%d MPG", v); } },

    "new_MPG_limit": { value:24, min:10, max:45, step:1, fmt:function (v) { return sprintf("%d MPG", v); } },
    "new_MPGs": { value:createDistribution([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 124, 299, 453, 896, 1051, 1009, 742, 1246, 1205, 1380, 948, 927, 515, 525, 340, 196, 196, 124, 175, 10, 31, 62, 0, 21, 0, 21, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, ]),
                  className:"distribution", comment:"miles-per-gallon distribution for new cars on sale",
                  href:"Notes/06-clunker.txt" },
    "eligible_new_MPGs": { className:"distribution", comment:"miles-per-gallon distribution for cars eligible to be traded to" },

    "average_new_MPG": { fmt:function (v) { return sprintf("%d MPG", v); } },
    
    "car_lifetime_miles": { value:150e3, min:10e3, max:1e6, step:10e3, fmt:function (v) { return commas(v) + " miles"; } },
    "fraction_lifetime_left": { value:0.25, min:0.01, max:1.0, step:0.01, fmt:function (v) { return sprintf("%d%%", Math.round(v * 100)); } },
    "average_miles_left": { fmt:function (v) { return commas(v) + " miles"; } },
    "gallons_saved_per_car": { fmt: function (v) { return commas(v) + " gallons"; } },
    "gallons_used_by_old_car": { fmt: function (v) { return commas(v) + " gallons"; } },
    "gallons_used_by_new_car": { fmt: function (v) { return commas(v) + " gallons"; } },
    "gallons_saved": { fmt: function (v) { return commas(v * 1e-6) + " million gallons"; } },

    "gallons_consumed_per_day": { value:377538000, min:1e6, max:1e10, step:1e6, fmt:function (v) { return commas(v * 1e-6) + " million gallons"; },
                                  href:"http://www.eia.gov/beta/api/qb.cfm?sdid=PET.MGFUPUS2.A" },
    "hours_per_day": { value:24, min:1, max:10000, step:1, fmt:function (v) { return sprintf("%d", v); } },
    "minutes_per_hour": { value:60, min:1, max:10000, step:1, fmt:function (v) { return sprintf("%d", v); } },
    "gallons_consumed_per_hour": { fmt: function (v) { return commas(v * 1e-6) + " million gallons"; } },
    "hours_of_gas": { fmt: function (v) { return sprintf("%.0f hours", v); } },
    
    "kg_CO2_per_gallon_gas": { value:8.87, min:0.01, max:100, step:0.01, fmt:function (v) { return sprintf("%.2f kg/gallon", v); },
                               href:"http://www.nhtsa.gov/CARS-archive/official-information/CARS-Report-to-Congress.pdf" },
    "CO2_per_CO2e": { value:0.95, min:0.01, max:1, step:0.01, fmt:function (v) { return sprintf("%.2f", v); },
                      href:"http://www.nhtsa.gov/CARS-archive/official-information/CARS-Report-to-Congress.pdf" },
    "kg_per_ton": { value:1000, min:1, max:1e6, step:10, fmt:function (v) { return sprintf("%d", v); } },
    "tons_CO2_saved": { fmt: function (v) { return sprintf("%.2f million tons", v * 1e-6); } },
    "tons_CO2e_saved": { fmt: function (v) { return sprintf("%.2f million tons", v * 1e-6); } },

    "tons_CO2e_emitted_yearly": { value:6983e6, min:1e6, max:1e10, step:10e6, fmt:function (v) { return commas(v * 1e-6) + " million tons" },
                                  href:"http://www.eia.gov/environment/emissions/ghg_report/pdf/tbl1.pdf" },
    "units_per_percent": { value:100, min:1, max:10000, step:1, fmt:function (v) { return sprintf("%d", v); } },
    "percent_annual_emissions": { fmt: function (v) { return sprintf("%.2f%%", v); } },
    
    "dollars_per_ton_CO2e": { fmt: function (v) { return "$" + commas(v); } },

    "dollars_per_gallon": { value:3.0, min:0.50, max:10, step:0.1, fmt:function (v) { return sprintf("$%.2f", v); } },
    "dollars_saved_buying_less_gas": { fmt:function (v) { return sprintf("$%.1f billion", v * 1e-9); } },
    "dollars_spent_on_balance": { fmt:function (v) { return sprintf("$%.2f billion", v * 1e-9); } },
    "dollars_per_ton_CO2e_on_balance": { fmt: function (v) { return ((v < 0) ? "-" : "") + "$" + commas(Math.abs(v)); } },
};

function commas (v) {
    return Math.round(v).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
}


//--------------------------------------------------------------------------------
//
//  tangle setup

var setupClunker = this.setupClunker = function () {
    var root = document.getElementById("clunker");
    var calculationRoot = document.getElementById("clunker-calculations");
    
    appendAllModelDivs(calculationRoot);
    attachVariableAttributesToSpans(root);
    initializeHelp(root);
    
    clunkerTangle = new Tangle(root, {
        initialize: function () {
            Object.keys(clunkerVariables).forEach(function (k) {
                this[k] = clunkerVariables[k].value;
            }, this);
            this["drag-help-message"] = isTouchDevice ? "left and right" : "with your mouse";
            this["click-help-message"] = isTouchDevice ? "Tap" : "Click";
        },
        update: getTangleUpdateFunction(),
    });
}

function appendAllModelDivs (calculationsRoot) {
    clunkerModels.forEach(function (m) {
        var div = getDivForModel(m);
        clunkerCalculationDivs[m.name] = div;
        calculationsRoot.appendChild(div);
    });
}

function attachVariableAttributesToSpans (root) {
    Object.keys(clunkerVariables).forEach(function (k) {
        var attr = clunkerVariables[k];
        var hasFormatFunction = (typeof(attr.fmt) == "function");
        if (hasFormatFunction) { Tangle.formats[k] = attr.fmt; }
        
        var spans = nodeArray(root.querySelectorAll('span[data-var="' + k + '"]'));
        spans.forEach(function (span) {
            if (hasFormatFunction) {
                span.setAttribute("data-format", k);
            }
            if (attr.min !== undefined) {
                span.setAttribute("data-min", attr.min);
                span.setAttribute("data-max", attr.max);
                span.setAttribute("data-step", attr.step);
            }
        });
    });
}

function getTangleUpdateFunction () {
    var updateScript = clunkerModels.map(function (m) { 
        return m.lines.map(function (line) {
            var string = (typeof(line) == "string") ? line : line.line;
            if (string === undefined) { return ""; }  // ignore comments, separators, etc

            string = string.replace(/params\./g, "this.");
            string = string.replace(/select (\S+) where (\S+) (.+)/g, "selectWhere($1, (function ($2) { return $2 $3; }).bind(this))");
            string = string.replace(/harmonic-average (.+)/g, "harmonicAverage($1)");
            return string + ";"
        }).join("\n");
    }).join("\n");
    
    return eval("(function () { " + updateScript + " })");
}


//--------------------------------------------------------------------------------
//
//  distribution functions

function createDistribution (array, comment) {
    return { values:array, selection_mask:array.map(function () { return 1; }), comment:comment };
}

function selectWhere (dist, f) {
    return { values:dist.values, selection_mask:dist.selection_mask.map(function (m,i) { return f(i) ? m : 0 }) };
}

function harmonicAverage (dist) {
    var n = dist.values.reduce(function (sum,v,i) { return sum + v * dist.selection_mask[i] * (i && (1/i)) }, 0);
    var d = dist.values.reduce(function (sum,v,i) { return sum + v * dist.selection_mask[i] }, 0);
    var avg = d / n;
    return isNaN(avg) ? 0 : avg;
}


//--------------------------------------------------------------------------------
//
//  calculation display

function getDivForModel (m) {
    var html = "";
    html += sprintf('<div class="figure-caption">calculations for “%s” <span class="comment">' + 
                    '(you can change assumptions in green)</span></div>', getNameForVariable(m.name));
    html += '<div class="analysis analysis-' + m.name + '">';
    html += m.lines.map(getHTMLForLine).join("\n");
    html += '</div>';
    
    return createElement("div", { "class":"calculation", "html":html });
}

function getHTMLForLine (line) {
    var string = (typeof(line) == "string") ? line : line.line;
    if (string === undefined) { return getHTMLForCommentLine(line); }

    var html = "";
    var columns = string.split(" = ");
    var isExpression = columns[1].match(/this\./);
    
    html += '<div class="line' + (isExpression ? " expression" : "") + '" style="' + (line.style || "") + '">';

    html += getHTMLForLineFragment(columns[0], " lhs");
    html += ' = ' + getHTMLForLineFragment(columns[1]);
    
    if (isExpression) {
        html += '<br>' + getHTMLForLineFragment(columns[0], " lhs dummy");
        html += ' = ';
        html += getHTMLForLineFragment(columns[0].replace(/this\./, "params."), "", true);
    }

    html += '</div>';
    return html;
}

function getHTMLForLineFragment (s, lhs, isResult) {
    return s.replace(/this\.(\w+)/g, function (_,k) { 
                return '<span class="token' + (lhs || "") + '" data-var="' + k + '">' + getNameForVariable(k) + '</span>' })
            .replace(/params\.(\w+)/g, function (_,k) {
                var attr = clunkerVariables[k];
                var clas = attr.className ? clunkerVariables[k].className :
                           isResult ? "" : 
                           (attr.min !== undefined) ? "adjustable-number" : "calculated-result";
                           
                var html = '<span class="' + clas + '" data-var="' + k + '"></span>';
                if (attr.href) { html += '<span class="cite"><a href="' + attr.href + '">(source)</a></span>'; }
                return html;
            });
}

function getNameForVariable (k) {
    return k.replace(/_/g, " ");
}

function getHTMLForCommentLine (line) {
    if (line.spacer) { return '<div class="spacer-' + line.spacer + '" style="' + (line.style || "") + '"></div>'; }
    if (line.separator) { return '<div class="separator" style="' + (line.style || "") + '"></div>'; }
    if (line.comment) { return '<div class="comment" style="' + (line.style || "") + '">' + line.comment + '</div>'; }
    return "";
}


//--------------------------------------------------------------------------------
//
//  interaction

function lockCalculatedResult (name) {
    var alreadyLocked = (clunkerCalculationDivs[name].style.display === "block");
    if (alreadyLocked) { name = ""; }  // unlock

    Object.keys(clunkerCalculationDivs).forEach(function (k) {
        var div = clunkerCalculationDivs[k];
        div.style.display = (name === k) ? "block" : "none";
    });
    
    var spans = nodeArray(clunkerTangle.element.querySelectorAll(".calculated-result"));
    spans.forEach(function (span) {
        if (span.getAttribute("data-var") === name) { addClass(span, "locked"); }
        else { removeClass(span, "locked"); }
    });
}

function setVariableHovering (name, hovering) {
    var spans = nodeArray(clunkerTangle.element.querySelectorAll('[data-var="' + name + '"]'));
    spans.forEach(function (span) {
        if (hovering) { addClass(span, "hovering"); }
        else { removeClass(span, "hovering"); }
    });
}


//--------------------------------------------------------------------------------
//
//  help

var calculationHelp;

function initializeHelp (root) {
    calculationHelp = createElement("div", { "class": "calculation-help" });
    root.insertBefore(calculationHelp, root.firstChild);
}

function setHelpShowingForElement (el, showing, text) {
    if (ancestorWithClass(el, "analysis")) { return; }  // no help for right column

    calculationHelp.style.display = showing ? "block" : "none";
    if (!showing) { return; }
    
    if (text && calculationHelp.innerHTML !== text) { calculationHelp.innerHTML = text; }
    
    var containerY = Math.round(calculationHelp.parentNode.getBoundingClientRect().top);
    var elY = Math.round(el.getBoundingClientRect().top);
    
    calculationHelp.style.marginTop = "" + (elY - containerY) + "px";
}


//--------------------------------------------------------------------------------
//
//  Tangle classes

var isAnyAdjustableNumberDragging = false;  // hack for dragging one value over another one


Tangle.classes["token"] = {

    initialize: function (element,options,tangle,variable) {
        this.element = element;
        this.variable = variable;

        this.isHovering = false;
        if (!isTouchDevice) {
            this.element.addEventListener("mouseenter", (function () { this.setHovering(true) }).bind(this));
            this.element.addEventListener("mouseleave", (function () { this.setHovering(false) }).bind(this));
        }
    },
    
    update: function () { },  // override tangle's default update
    
    setHovering: function (hovering) {
        this.isHovering = hovering;
        if (isAnyAdjustableNumberDragging) { return; }
        setVariableHovering(this.variable, this.isActive());
    },
    
    isActive: function () {
        return this.isHovering && !isAnyAdjustableNumberDragging;
    },
};


Tangle.classes["calculated-result"] = {

    initialize: function (element,options,tangle,variable) {
        this.element = element;
        this.variable = variable;
        this.wantsHelp = !this.element.getAttribute("data-no-help");

        this.isHovering = false;
        if (!isTouchDevice) {
            this.element.addEventListener("mouseenter", (function () { this.setHovering(true) }).bind(this));
            this.element.addEventListener("mouseleave", (function () { this.setHovering(false) }).bind(this));
        }

        this.element.onclick = (function () {
            lockCalculatedResult(variable);
            this.updateHelp()
        }).bind(this);
    },

    setHovering: function (hovering) {
        this.isHovering = hovering;
        if (isAnyAdjustableNumberDragging) { return; }
        setVariableHovering(this.variable, this.isActive());
        this.updateHelp();
    },
    
    updateHelp: function () {
        if (this.wantsHelp) {
            var text = hasClass(this.element, "locked") ? "click to hide calculations" : "click to see calculations";
            setHelpShowingForElement(this.element, this.isActive(), text);
        }
    },
    
    isActive: function () {
        return this.isHovering && !isAnyAdjustableNumberDragging;
    },
};


Tangle.classes["adjustable-number"] = {

    initialize: function (element, options, tangle, variable) {
        this.element = element;
        this.tangle = tangle;
        this.variable = variable;

        this.min = (options.min !== undefined) ? parseFloat(options.min) : 1;
        this.max = (options.max !== undefined) ? parseFloat(options.max) : 10;
        this.step = (options.step !== undefined) ? parseFloat(options.step) : 1;
        
        this.initializeHover();
        this.initializeDrag();
    },


    // hover
    
    initializeHover: function () {
        this.isHovering = false;
        if (!isTouchDevice) {
            this.element.addEventListener("mouseenter", (function () { this.setHovering(true) }).bind(this));
            this.element.addEventListener("mouseleave", (function () { this.setHovering(false) }).bind(this));
        }
    },
    
    setHovering: function (hovering) {
        this.isHovering = hovering;
        this.updateRolloverEffects();
    },
    
    updateRolloverEffects: function (down) {
        if (!down && isAnyAdjustableNumberDragging) { return; }  // ignore if dragging a different number
        this.updateStyle();
        this.updateCursor();
        this.updateHelp();
    },
    
    isActive: function () {
        return this.isDragging || (this.isHovering && !isAnyAdjustableNumberDragging);
    },

    updateStyle: function () {
        setVariableHovering(this.variable, this.isActive());

        if (this.isDragging) { addClass(this.element, "dragging"); }
        else { removeClass(this.element, "dragging"); }
    },

    updateCursor: function () {
        var body = document.body;
        if (this.isActive()) { addClass(body,"TKCursorDragHorizontal"); }
        else { removeClass(body,"TKCursorDragHorizontal"); }
    },

    updateHelp: function () {
        setHelpShowingForElement(this.element, this.isActive(), "drag the number left or right");
    },


    // drag
    
    initializeDrag: function () {
        this.isDragging = false;
        makeTouchable(this.element, this);
    },
    
    touchDown: function (e,x,y) {
        isAnyAdjustableNumberDragging = true;
        this.isDragging = true;
        this.valueAtMouseDown = this.tangle.getValue(this.variable);
        this.xAtMouseDown = x;

        this.updateRolloverEffects(true);
        this.updateStyle();
    },
    
    touchMove: function (e,x,y) {
        var dx = x - this.xAtMouseDown;
        var unclippedValue = this.valueAtMouseDown + dx / 5 * this.step;
        var value = Math.min(this.max, Math.max(this.min, Math.round(unclippedValue / this.step) * this.step));
        
        this.tangle.setValue(this.variable, value);
        this.updateHelp();
    },
    
    touchUp: function (e,x,y) {
        isAnyAdjustableNumberDragging = false;
        this.isDragging = false;

        this.updateRolloverEffects();
        this.updateStyle();
        this.updateHelp();
    }
};


Tangle.classes["distribution"] = {

    initialize: function (element,options,tangle,variable) {
        this.element = element;
        this.tangle = tangle;
        this.variable = variable;
        this.height = 18;
    },
    
    update: function () {
        if (!this.bars) {
            this.bars = this.createBars();
            this.fills = this.bars.map(function (bar) { return bar.querySelector(".fill"); });
        }

        var dist = this.tangle.getValue(this.variable);
        var maxValue = dist.values.reduce(function (max,v) { return (v > max) ? v : max }, 0);
        
        this.fills.forEach(function (fill, i) {
            var fillHeight = Math.round(dist.values[i] / maxValue * this.height);
            fill.style.height = fillHeight + "px";
            this.bars[i].className = dist.selection_mask[i] ? "bar selected" : "bar";
        }, this);
    },
    
    createBars: function () {
        var dist = this.tangle.getValue(this.variable);
        var barContainer = createElement("div", { "class":"bars" });
        this.element.appendChild(barContainer);
        
        var bars = dist.values.map(function (v,i) {
            var bar = createElement("div", { "class":"bar", "html":'<div class="fill"></div>' });
            bar.onmouseenter = (function () { this.mouseEnteredBar(bar,i); }).bind(this);
            bar.onmouseleave = (function () { this.mouseLeftBar(bar,i); }).bind(this);
            barContainer.appendChild(bar);
            return bar;
        }, this);
        
        var comment = clunkerVariables[this.variable].comment;
        if (comment) {
            this.commentDiv = createElement("div", { "class":"comment", "html":comment });
            this.element.appendChild(this.commentDiv);
        }
        
        this.labelDiv = createElement("div", { "class":"label" });
        this.element.appendChild(this.labelDiv);

        return bars;
    },
    
    mouseEnteredBar: function (bar, i) {
        this.labelDiv.innerHTML = i + " MPG";
        this.labelDiv.style.left = (i*6 - 25) + "px";
        this.labelDiv.style.display = "block";
        if (this.commentDiv) { this.commentDiv.style.visibility = "hidden"; }
    },
    mouseLeftBar: function (bar, i) {
        this.labelDiv.style.display = "none";
        if (this.commentDiv) { this.commentDiv.style.visibility = "visible"; }
    },
};


})();


================================================
FILE: Script/main.js
================================================
//
//  main.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//

var isTouchDevice = !!("ontouchstart" in window);

window.onload = function () {
    if (isTouchDevice) { addClass(document.body, "touch-device"); }

    chain([
        setupTableOfContents,
        loadScripts,
        preloadImages,
        setupCarbonBudget,
        setupClunker,
        setupPreviewImages,
        setupDynamicToolsVideos,
        setupAutocompleteVideo,
    ]);
    
    function chain (funcs) {
        setTimeout(next, 10);
        function next () {
            if (funcs.length == 0) { return; }
            (funcs.shift())();
            setTimeout(next, 10);
        }
    }
}


//---------------------------------------------------------------------
// toc

function setupTableOfContents () {
    var template = document.getElementById("toc-template");
    var tocs = nodeArray(document.querySelectorAll(".toc"));
    
    tocs.forEach(function (toc) {
        if (toc === template) { return; }
        toc.innerHTML = template.innerHTML;
        
        var activeChapter = toc.querySelector(".toc-" + toc.id);
        activeChapter.className += " toc-active";
    });
}


//---------------------------------------------------------------------
// scripts

var scripts = {};

function loadScripts () {
    var divs = nodeArray(document.querySelectorAll(".script"));
    loadNextDiv();
    
    function loadNextDiv () {
        if (divs.length == 0) { return; }
        var div = divs.shift();
        var params = div.getAttribute("data-script").split(/\s/);

        var name = params.shift();
        params.unshift(div);
        
        var func = scripts[name];
        func.apply(undefined, params);
        
        window.setTimeout(loadNextDiv, 5); 
    }
}

scripts["svg"] = function (div, name) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "Images/" + name + ".svg");
    xhr.onload = function () { div.innerHTML = xhr.responseText };
    xhr.send();
}

scripts["chart"] = function (div, name) {
    placeChart(div, name);
};


//---------------------------------------------------------------------
// videos

function setupDynamicToolsVideos () {
    var divs = nodeArray(document.querySelectorAll(".dynamic-tools-thumbnail"));
    divs.forEach(function (div) {
        var video = div.querySelector("video");
        var img = div.querySelector("img");
        if (!video || !img) { return; }
        div.addEventListener("mouseenter", function () {
            video.play();
            img.style.visibility = "hidden";
        });
        div.addEventListener("mouseleave", function () {
            img.style.visibility = "visible";
            video.pause();
            video.currentTime = 0;
        });
    });
}


//---------------------------------------------------------------------
// preload images

var mainPreloadedImages;

function preloadImages () {
    var urls = [ "Images/01-carbon-budget-knob-down.png" ];
    mainPreloadedImages = urls.map(function (url) {
        var image = new Image();
        image.src = url;
        return image;
    });
}


//---------------------------------------------------------------------
// util

function nodeArray (nodeList) {
    return Array.prototype.slice.call(nodeList);
}

function createElement (tag, properties) {
    var el = document.createElement(tag);
    Object.getOwnPropertyNames(properties || {}).forEach(function (k) {
        if (k === "html") { el.innerHTML = properties[k]; }
        else { el.setAttribute(k, properties[k]); }
    });
    return el;
}

function hasClass (el,clas) {
    var classes = (el.className || "").split(" ");
    return classes.some(function (c) { return c === clas; });
}

function addClass (el,clas) {
    if (hasClass(el,clas)) { return; }
    el.className = (el.className !== undefined && el.className.length) ? (el.className + " " + clas) : clas;
}

function removeClass (el,clas) {
    var classes = (el.className || "").split(" ");
    var newName = classes.filter(function (c) { return c !== clas; }).join(" ");
    if (el.className !== newName) { el.className = newName; }
}

function getInheritedAttribute (el, attr) {
    for (var node = el; node && node !== document.body; node = node.parentNode) {
        var a = node.getAttribute(attr);
        if (a) { return a; }
    }
    return undefined;
}

function ancestorWithClass (el, clas) {
    if (Array.isArray(clas)) {
        return clas.reduce(function (a,c) { return a || ancestorWithClass(el, c); }, null);
    }

    for (var node = el; node && node !== document.body; node = node.parentNode) {
        if (hasClass(node, clas)) { return node; }
    }
    return null;
}

function ancestorWithTagName (el, tag) {
    if (Array.isArray(tag)) {
        return tag.reduce(function (a,c) { return a || ancestorWithTagName(el, c); }, null);
    }

    for (var node = el; node && node !== document.body; node = node.parentNode) {
        var t = (node.tagName || "").toLowerCase();
        if (t && t === tag) { return node; }
    }
    return null;
}

function lerp (a,b,t) { return a + (b - a) * t; };
function remap (x,fromLow,fromHigh,toLow,toHigh) { return lerp(toLow, toHigh, (x - fromLow) / (fromHigh - fromLow)); };



================================================
FILE: Script/previews.js
================================================
//
//  previews.js
//  What Can A Technologist Do About Climate Change?
//
//  Bret Victor, November 2015
//  MIT open-source license.
//

var previewsComeFromAWS = true;
var previewImagesByURL = {};

var setupPreviewImages = this.setupPreviewImages = function () {
    if ("ontouchstart" in window) { return; }  // no previews on touch device

    setupRecentScroll();
    
    var links = getPreviewLinks();
    var names = getPreviewNamesForLinks(links);
    
    setupPreviewSubset(names,links,0,3,0);
    setupPreviewSubset(names,links,3,30,2000);
    setupPreviewSubset(names,links,30,100,3000);
    setupPreviewSubset(names,links,100,1000,4000);
};

function setupPreviewSubset (names, links, from, to, timeout) {
    setTimeout(function () {
        loadPreviewImagesWithNames(names.slice(from,to));
        setupPreviewLinks(links.slice(0,to));
    }, timeout || 0);
}

function loadPreviewImagesWithNames (names) {
    names.forEach(function (name) {
        var image = new Image();
        var url = getPreviewImageURLForName(name);
        image.src = url;
        previewImagesByURL[url] = image;
    });
}

function setupPreviewLinks (links) {
    links.forEach(function (link) {
        var url = getPreviewImageURLForLinkURL(link.getAttribute("href") || "");
        if (previewImagesByURL[url]) {
            setupPreviewLink(link, url);
        }
    });
}

function setupPreviewLink (link, url) {
    if (link.onmouseenter) { return; }

    var containerID = getInheritedAttribute(link, "data-preview-container");
    var cite = ancestorWithClass(link, "cite");
    var container = containerID ? document.getElementById(containerID) : cite ? cite.parentNode : undefined;

    var previewHeight = 320;
    var previewBorderOffset = 0;

    link.onmouseenter = function () {
        if (recentlyScrolled) { return; }
    
        var windowHeight = window.innerHeight;
        var linkY = Math.round(link.getBoundingClientRect().top);
        var previewY = Math.round(Math.max(10, Math.min(windowHeight - previewHeight - 10, linkY - previewHeight/3)));
        var previewOffset = (containerID ? 0 : (previewY - linkY)) - previewBorderOffset;
    
        var preview = createElement("img", { 
            "class": "link-preview", 
            "style": "margin-top:" + previewOffset + "px",
            "src": url,
        });

        if (container) {
            container.insertBefore(preview, container.firstChild);
        }
        else {
            link.parentNode.insertBefore(preview, link);
        }
        
        function removePreview () {
            if (preview && preview.parentNode) {
                preview.parentNode.removeChild(preview);
                preview = undefined;
            }
        }
    
        link.onmouseleave = removePreview;
        link.onclick = removePreview;
    };
}

function getPreviewLinks () {
    var excludedClasses = ["column-right", "no-preview", "figure", "toc" ];
    return nodeArray(document.body.getElementsByTagName("a")).filter(function (link) {
        return !ancestorWithTagName(link, "svg") &&
               !ancestorWithClass(link, excludedClasses) &&
               link.getAttribute("href") && link.getAttribute("href").substr(0,1) !== "#";
    });
}

function getPreviewURLsForLinks (links) {
    return links.map(function (link) { return link.getAttribute("href"); });
}

function getPreviewNamesForLinks (links) {
    return getPreviewURLsForLinks(links).map(getPreviewNameForLinkURL);
}


// don't show when scrolling, only when mousing deliberately

var recentlyScrolled = false;
var recentScrollTime = 0;

function setupRecentScroll () {
    window.addEventListener("scroll", function () {
        recentlyScrolled = true;
        recentScrollTime = Date.now();
    });
    document.body.addEventListener("mousemove", function () {
        if (!recentlyScrolled) { return; }
        var msSinceScroll = Date.now() - recentScrollTime;  // mousemove events are auto-generated after scroll
        if (msSinceScroll > 100) { recentlyScrolled = false; }      // so make sure this isn't one of those
    });
}


// preview url

function getPreviewNameForLinkURL (url) {
    return url.replace(/^h\w+\W+/,"").replace(/\/$/, "").replace(/\W+/g, "-") + ".jpg";
}

function getPreviewImageURLForLinkURL (url) {
    var name = getPreviewNameForLinkURL(url);
    return getPreviewImageURLForName(name);
}

function getPreviewImageURLForName (name) {
    var prefix = previewsComeFromAWS ? "http://s3.amazonaws.com/worrydream.com/ClimateChange/" : "";
    return prefix + "PreviewImages/" + name;
}



================================================
FILE: data.html
================================================
<!DOCTYPE html>
<html><head>
    <meta charset="UTF-8">
    <base target="_top">
    <script src="Script/chart-data.js" type="text/javascript"></script>
</head>
<body>
<pre id="result">
</pre>

<script type="text/javascript">
    var id = (window.location.search.match(/id=([^\&]+)/) || [])[1];
    var data = chart_data[id || ""];
    if (data) {
        var text = document.createTextNode(JSON.stringify(data, null, 2));
        document.getElementById("result").appendChild(text);
    }
</script>

</body></html>


================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html><head>
    <meta charset="UTF-8">
    <base target="_top">
    <title>What can a technologist do about climate change? A personal view.</title>

    <link href="style.css" rel="stylesheet" type="text/css">

    <script src="Lib/sprintf.js" type="text/javascript"></script>
    <script src="Lib/Tangle.js" type="text/javascript"></script>
    <script src="Lib/Touchable.js" type="text/javascript"></script>

    <script src="Script/main.js" type="text/javascript"></script>
    <script src="Script/clunker.js" type="text/javascript"></script>
    <script src="Script/carbon-budget.js" type="text/javascript"></script>
    <script src="Script/previews.js" type="text/javascript"></script>
    <script src="Script/chart-data.js" type="text/javascript"></script>
    <script src="Script/charts.js" type="text/javascript"></script>
    <script src="Script/autocomplete-video.js" type="text/javascript"></script>
</head>

<body>
    

<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- header -->

<div class="header no-preview">
    <div class="header-quote-block">
        <div class="header-quotes">
            <div>People say “this is a Manhattan Project, this an Apollo Project”.  Sorry, those are science projects.  Fusion is a Manhattan Project or an Apollo Project... The rest of this is more like <b>retooling for World War II</b>, except with everyone playing on the same team.</div>
            <div class="who">— Saul Griffith, on converting the world to clean energy</div>
            <div class="two">This has not been a scientist’s war; it has been a war in which all have had a part.</div>
            <div class="who2">— Vannevar Bush, on World War II</div>
        </div>
    </div>

    <div class="header-plain">
        <img src="Images/00-page-header.jpg">
        <h1>What can a technologist do about climate change?</h1>
        <div class="subtitle">(A personal view)</div>
        <div class="byline"><a href="http://worrydream.com/">Bret Victor</a> / November 2015</div>
    </div>

    <div class="header-title-block">
        <div class="header-titles">
            <img src="Images/00-titles.png" width="561" height="108">
            <a href="http://worrydream.com/"><div class="header-title-selflink"></div></a>
        </div>
    </div>
</div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- intro -->

<!-- begin chapter --><div class="chapter">
<!-- first left-column --><div class="row"><div class="column-left">

<p>This started with a tweet.  I’m embarrassed how often that happens.</p>

<p>Frustrated by a sense of <a href="http://www.vox.com/2015/8/10/9124145/effective-altruism-global-ai">global mispriorities</a>, I blurted out some snarky and mildly regrettable <a href="https://twitter.com/worrydream/status/631361688931991552">tweets</a> on the lack of attention to climate change in the tech industry (Twitter being a sublime medium for the snarky and regrettable).  Climate change is the problem of our time, it’s everyone’s problem, and most of our problem-solvers are assuming that someone else will solve it.</p>

<p>I’m grateful to one problem-solver, who wrote to ask for specifics —</p>

<!-- right-column --></div><div class="column-right">

<img src="Images/00-tweets.jpg" width="271" height="196">

<div style="display:none;">
<div>Bret Victor @worrydream - Aug 11<br>Worrying about sentient AI as the ice caps melt is like standing on the tracks as the train rushes in, worrying about being hit by lightning</div>
<div>Bret Victor @worrydream - Aug 12<br>If any "founders" out there want to "disrupt" our 401 ppm atmospheric CO2, or "moonshot" ocean acidification, that would be cool</div>
<div>Bret Victor @worrydream - Aug 12<br>"minimum viable planet"</div>
</div>

<!-- close row --></div></div>

<div class="big-quote">“How do you think the tech community (startup community, or any community) can contribute to tech and/or policy solutions on a global scale?”</div>

<!-- first left-column --><div class="row"><div class="column-left">

<p>The notes below are my attempt to answer that question.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>This is a “personal view”, biased by my experiences and idiosyncrasies.  I’ve followed the climate situation for some time, including working on Al Gore’s book <a href="http://pushpoppress.com/ourchoice/">Our Choice</a>, but I can’t hope to convey the full picture — just a sliver that’s visible from where I’m standing.  I urge you to talk to many scientists and engineers involved in climate analysis and energy, and see for yourself what the needs are and how you can contribute.</p>

<p>This is aimed at people in the tech industry, and is more about what you can do with your career than at a hackathon.  I’m not going to discuss policy and regulation, although they’re no less important than technological innovation.  A good way to think about it, via Saul Griffith, is that <i>it’s the role of technologists to create options for policy-makers.</i></p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:4px;">everything that needs to be done about climate change</div>
<img src="Images/00-scope-0.png" width="440" height="26">
</div>

<div class="figure">
<div class="figure-caption" style="margin-top:16px;margin-bottom:4px;">what you’ll read about here</div>
<img src="Images/00-scope-1.png" width="440" height="26">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>I’m also only going to directly discuss technology related to the <i>primary cause</i> of climate change (the burning of fossil fuels), although there are technological needs related to other causes (<a href="https://en.wikipedia.org/wiki/Climate_change_and_agriculture#Livestock">livestock</a>, <a href="https://en.wikipedia.org/wiki/Deforestation_and_climate_change">deforestation</a>, <a href="http://www.ted.com/talks/hans_rosling_on_global_population_growth#t-301019">global poverty</a>), as well as mitigating <i>symptoms</i> of climate change (<a href="http://www.theguardian.com/environment/2015/apr/27/extreme-weather-already-on-increase-due-to-climate-change-study-finds">droughts and storms</a>, <a href="https://en.wikipedia.org/wiki/Climate_change_and_ecosystems">ecosystem damage</a>, <a href="http://www.theguardian.com/commentisfree/2015/aug/18/mass-migration-crisis-refugees-climate-change">mass migrations</a>).</p>

<!-- end chapter --></div></div></div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- table of contents template -->

<div id="toc-template" class="toc">
    <div class="toc-background"></div><div class="top-stripe"></div>
    <div class="toc-contents">
        <div class="toc-chapter toc-funding">
            <a class="toc-chapter-name" href="#funding">Funding</a>
            <a class="toc-section-name" href="#funding-public">Public investment</a>
            <a class="toc-section-name" href="#funding-private">Private investment</a>
        </div><div class="toc-chapter toc-production">
            <a class="toc-chapter-name" href="#production">Producing Energy</a>
            <a class="toc-section-name" href="#production-stuff">The stuff around the thing</a>
            <a class="toc-section-name" href="#production-computation">Computation</a>
        </div><div class="toc-chapter toc-moving">
            <a class="toc-chapter-name" href="#moving">Moving Energy</a>
            <a class="toc-section-name" href="#moving-networking">Networking<br><span>(moving in space)</span></a>
            <a class="toc-section-name" href="#moving-storage">Storage<br><span>(moving in time)</span></a>
        </div><div class="toc-chapter toc-consumption">
            <a class="toc-chapter-name" href="#consumption">Consuming Energy</a>
            <a class="toc-section-name" href="#consumption-transportation">Transportation<br><span>(consuming what?)</span></a>
            <a class="toc-section-name" href="#consumption-coordination">Coordination<br><span>(consuming when?)</span></a>
            <a class="toc-section-name" href="#consumption-efficiency">Efficiency<br><span>(consuming how much?)</span></a>
        </div><div class="toc-chapter toc-tools">
            <a class="toc-chapter-name" href="#tools">Tools for Scientists &amp; Engineers</a>
            <a class="toc-section-name" href="#tools-technical">Technical computing</a>
            <a class="toc-section-name" href="#tools-modeling">Tools for modeling physical systems</a>
            <a class="toc-section-name" href="#tools-controlling">Tools for controlling physical systems</a>
            <a class="toc-section-name" href="#tools-finding">Tools for problem-finding</a>
        </div><div class="toc-chapter toc-media">
            <a class="toc-chapter-name" href="#media">Media for Understanding Situations</a>
            <a class="toc-section-name" href="#media-debate">Model-driven debate</a>
            <a class="toc-section-name" href="#media-reading">Model-driven reading</a>
            <a class="toc-section-name" href="#media-writing">Model-driven authoring</a>
        </div><div class="toc-chapter toc-coda">
            <a class="toc-chapter-name" href="#coda">Also this</a>
            <a class="toc-section-name" href="#coda-other">Other technology</a>
            <a class="toc-section-name" href="#coda-morale">Morale</a>
            <a class="toc-section-name" href="#coda-see">The world is not what you see</a>
        </div>
    </div>
</div><!-- toc -->


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- funding -->

<div id="funding" class="toc"></div>
<h2>Funding</h2>

<!-- begin chapter --><div class="chapter">
<!-- first left-column --><div class="row"><div class="column-left">

<p>I won’t say much about this, but I can’t leave it out. Available funding sources, and the interests and attitudes of the funders, have always had an enormous effect on what technology comes to exist in the world.  In a time of crisis, it’s the responsibility of those holding the capital to sponsor work on averting the crisis.  That is not happening.</p>

<h3 id="funding-public"><a href="#funding-public">Public investment</a></h3>

<!-- close row --></div></div>

<div class="script" data-script="svg 01-public-structure" style="width:940px;height:302px;"></div>

<div class="public-structure-captions" data-preview-container="public-structure-preview-container">

<div class="public-structure-caption" style="left:0px;width:142px;">The primary source of public funding in the U.S. for “I’ve got a crazy new idea for energy” is <a href="http://arpa-e.energy.gov">ARPA-E</a>.  Last year it granted <a href="http://arpa-e.energy.gov/sites/default/files/ARPA-E%202016%20Budget.pdf">$280 million</a>.</div>

<div class="public-structure-caption" style="left:172px;width:191px;">Incremental innovation is supported by the <a href="http://energy.gov">DOE</a>’s <a href="http://energy.gov/eere/office-energy-efficiency-renewable-energy">Office of Energy Efficiency &amp; Renewable Energy</a>, which has a <a href="http://www5.eere.energy.gov/office_eere/program_budget_formulation.php">$2 billion</a> annual budget for a wide range of initiatives.</div>

<div class="public-structure-caption" style="left:385px;width:126px;">The <a href="http://energy.gov">DOE</a> also funds the <a href="http://energy.gov/national-labs">national labs</a>, which do a lot of energy research.</div>

<div class="public-structure-caption" style="left:596px;width:161px;">The <a href="http://www.nsf.gov">NSF</a>’s <a href="http://www.nsf.gov/funding/pgm_summ.jsp?pims_id=501026">Energy for Sustainability</a> program gives out <a href="http://www.nsf.gov/awardsearch/advancedSearchResult?WT.si_n=ClickedAbstractsRecentAwards&WT.si_x=1&WT.si_cs=1&WT.z_pims_id=501026&ProgEleCode=7644&BooleanElement=Any&BooleanRef=Any&ActiveAwards=true">$18 million</a> annually for academic research.</div>

<div class="public-structure-caption" style="left:772px;width:173px;">Public funding can also be found at the state level, such as the <a href="http://www.energy.ca.gov">California Energy Commission</a>’s <a href="http://www.energy.ca.gov/contracts/epic.html">EPIC</a> program, which has a <a href="http://www.energy.ca.gov/2014publications/CEC-500-2014-038/CEC-500-2014-038-CMF.pdf">$130 million</a> annual budget.</div>

</div>

<!-- first left-column --><div class="row"><div class="column-left">

<div id="public-structure-preview-container"></div>

<p>Possibly the largest source of public funding is in the form of <a href="http://energy.gov/eere/slsc/downloads/guide-federal-financing-energy-efficiency-and-clean-energy-deployment">financing programs</a>, such as <a href="http://energy.gov/lpo/about-us-home">loan guarantees</a> and <a href="http://energy.gov/savings/renewable-electricity-production-tax-credit-ptc">tax credits</a>.</p>

<blockquote>
[The U.S. energy loan program] literally kick-started the whole utility-scale photovoltaic industry... The program funded the first of five huge solar projects in the West... Before that, developers couldn’t get money from private lenders. But now, with proven business models, they can. <span class="cite"><a href="http://www.npr.org/2014/11/13/363572151/after-solyndra-loss-u-s-energy-loan-program-turning-a-profit">(source)</a></span></blockquote>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>It’s great that this funding exists, but let’s be clear — it’s a pittance. If we take Saul Griffith’s quote at face value and accept that addressing climate change will take a concerted global effort comparable to World War II, consider that the U.S. spent about <a href="http://cironline.org/sites/default/files/legacy/files/June2010CRScostofuswars.pdf">$4 trillion</a> in today’s dollars to “fight the enemy” at that time.  Our present enemy is more threatening, and our financial commitment to the fight is several orders of magnitude off.</p>

<blockquote><span class="author">(Naomi Klein)</span> There is... no scenario in which we can avoid wartime levels of spending in the public sector — not if we are serious about preventing catastrophic levels of warming, and minimizing the destructive potential of the coming storms. <span class="cite"><a href="http://bit.ly/1ZJtgdb">(source)</a></span>
</blockquote>

<p>In the meantime, the fossil fuel industry is being subsidized at about <a href="http://www.worldenergyoutlook.org/resources/energysubsidies/">half a trillion dollars a year</a>.</p>

<p>Public funding for clean energy is a problem to be solved.  It’s not a technology problem.  But it’s a blocker that prevents us from getting to the technology problems.</p>

<h3 id="funding-private"><a href="#funding-private">Private investment</a></h3>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:4px;">U.S. military spending per year <span class="amount">$610 billon</span>
<span class="cite"><a href="http://www.gpo.gov/fdsys/search/pagedetails.action;jsessionid=sLzjW3BPp1ZBpRCMnN7kfDp2nF3hHqyw6MmvprCLxlf4DyyLdj6X!1929810491!-352118568?granuleId=BUDGET-2015-TAB-5-1&packageId=BUDGET-2015-TAB">(source)</a></span></div>
<img src="Images/01-publicfunding-0.png" width="438" height="178">
</div>

<div class="figure">
<div class="figure-caption" style="margin-top:16px;margin-bottom:4px;">U.S. venture capital investment per year <span class="amount">$48 billon</span>
<span class="cite"><a href="http://nvca.org/pressreleases/annual-venture-capital-investment-tops-48-billion-2014-reaching-highest-level-decade-according-moneytree-report/">(source)</a></span></div>
<img src="Images/01-publicfunding-1.png" width="438" height="16">
</div>

<div class="figure">
<div class="figure-caption" style="margin-top:16px;margin-bottom:4px;">Office of Energy Efficiency &amp; Renewable Energy budget  <span class="amount">$2 billon</span>
<span class="cite"><a href="http://www5.eere.energy.gov/office_eere/program_budget_formulation.php">(source)</a></span></div>
<img src="Images/01-publicfunding-2.png" width="438" height="4">
</div>

<div class="figure">
<div class="figure-caption" style="margin-top:16px;margin-bottom:4px;">ARPA-E budget <span class="amount">$0.3 billon</span>
<span class="cite"><a href="http://arpa-e.energy.gov/sites/default/files/ARPA-E%202016%20Budget.pdf">(source)</a></span></div>
<img src="Images/01-publicfunding-3.png" width="438" height="4">
</div>

<div class="figure">
<div class="figure-caption" style="margin-top:16px;margin-bottom:4px;">NSF Energy for Sustainability budget <span class="amount">$0.02 billon</span>
<span class="cite"><a href="http://www.nsf.gov/awardsearch/advancedSearchResult?WT.si_n=ClickedAbstractsRecentAwards&WT.si_x=1&WT.si_cs=1&WT.z_pims_id=501026&ProgEleCode=7644&BooleanElement=Any&BooleanRef=Any&ActiveAwards=true">(source)</a></span></div>
<img src="Images/01-publicfunding-4.png" width="438" height="1">
</div>


<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>You can <a href="http://www.wired.com/2012/01/ff_solyndra/">read the story</a> of the so-called “cleantech bubble”.  In brief — between 2008 and 2011, about $15 billion of enthusiastic venture capital went into energy-related startups.  There were a few major failures, investors got spooked, and cleantech became taboo.</p>

<p>Late-stage venture funding has dwindled, and early-stage funding has all but disappeared.  Founders spend their days scrounging instead of building.  Consider the American energy storage company <a href="http://www.primuspower.com/">Primus Power</a>, which had to raise its <a href="http://www.marketwired.com/press-release/primus-power-secures-20-million-in-first-close-of-series-c-funding-1875328.htm">series C from a South African platinum company</a>, and <a href="http://www.greentechmedia.com/articles/read/primus-power-raises-25m-to-bring-flow-batteries-to-kazakhstan">series D from Kazakhstan</a>.</p>

<p>The human race uses <a href="http://www.iea.org/publications/freepublications/publication/KeyWorld2014.pdf">18 terawatts</a>, and will for the foreseeable future.  So there are basically only two scenarios for investors as a collective:</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 01-private-late" style="width:440px;height:97px;"></div>
<div class="script figure" data-script="chart 01-private-early" style="width:440px;height:97px;margin-top:14px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<div class="indent">
<p>(a) invest in clean energy immediately; clean energy takes over the <a href="http://selectusa.commerce.gov/industry-snapshots/energy-industry-united-states">$6&nbsp;trillion global energy market</a>; investors get a nice piece of that.</p>

<p>(b) don’t invest in clean energy immediately; fossil fuels <a href="http://www.carbontracker.org/wp-content/uploads/2014/09/Unburnable-Carbon-Full-rev2-1.pdf">burn past our carbon budget</a>; investors inherit a <a href="http://daniellefong.com/2012/08/27/defusing-the-carbon-bomb/">cinder</a>.</p>
</div>

<p>Scenario (a) seems like the most rational plan for everyone, in the long term.  The fact that most investors’ short-term incentives are structured to prefer scenario (b) is a critical problem to be solved.  Again, it’s not a technology problem, but it’s a blocker that prevents us from getting to the technology problems.</p>

<!-- right-column --></div><div class="column-right">

<div id="carbon-budget-figure" class="figure" style="padding-bottom:10px;">
<div class="figure-caption" style="margin-bottom:8px;">world carbon emissions (in GtCO<sub>2</sub>/yr) and carbon budget
<span class="cite"><a href="Notes/03-carbon-budget.txt">(source)</a></span></div>
<div style="position:relative;">
    <div class="script" data-script="svg 01-carbon-budget" style="width:440px;height:192px;"></div>
    <div class="carbon-budget-knob" data-var="knobPoint"></div>
    <div class="carbon-budget-knob-help">drag</div>
</div>
</div>


<!-- end chapter --></div></div></div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- energy production -->

<div id="production" class="toc"></div>
<h2>Producing Energy</h2>

<!-- begin chapter --><div class="chapter">

<div class="figure" style="margin-top:0;margin-left:105px;margin-bottom:30px;position:relative;">
    <img src="Images/02-sankey.png" width="730" height="324">
    <div class="script" data-script="svg 02-sankey" style="position:absolute;left:0;top:0;width:730px;height:324px;"></div>
    <span class="cite" style="position:absolute;left:131px;top:-5px;"><a href="https://flowcharts.llnl.gov">(source)</a></span>
</div>

<!-- first left-column --><div class="row"><div class="column-left">

<p>The primary cause of global warming is the dumping of carbon dioxide into the sky.</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 02-pollutants" style="width:440px;height:97px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The primary cause of that is the burning of coal, natural gas, and petroleum in order to generate electricity and move vehicles around.</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 02-sources" style="width:440px;height:58px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>In order to stop dumping carbon dioxide into the sky, the world will have to generate its energy “cleanly”.  For the purposes of this essay, that will mean mostly via solar and wind, although geothermal, hydroelectric, biomass, and nuclear will all have parts to play.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>This is well-known, but the scale and rate of change required is often unappreciated.  Saul Griffith has a <a href="http://library.fora.tv/2009/01/16/Saul_Griffith_Climate_Change_Recalculated/Griffith_Proposes_Massive_Increase_in_Green_Energy">good bit about this</a>, suggesting that what’s needed is not throwing up a few solar panels, but a major industrial shift comparable to <a href="http://www.ibiblio.org/hyperwar/USA/BigL/BigL-1.html">retooling for World War II</a>.</p>

<p>In 1940 through 1942, U.S. war-related industrial production tripled each year.  That’s over twice as fast as <a href="https://en.wikipedia.org/wiki/Moore%27s_law">Moore’s law</a>.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:-33px;">U.S. gross national product, WWII<br><span class="cite"><a href="http://www.ibiblio.org/hyperwar/USA/BigL/BigL-1.html" style="margin-left:0;">(source)</a></span></div>
<div class="script" data-script="svg 02-ww2" style="width:440px;height:190px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>In order to avoid the more <a href="http://www.informationisbeautiful.net/visualizations/how-many-gigatons-of-co2">catastrophic climate scenarios</a>, global production and adoption of clean energy technology will have to scale at similar rates — but <a href="refs/DanielleFong-GrowthRateRequiredInEnergyStorage.pdf">continuously for 15 years or more</a>.</p>

<p>The catalyst for such a scale-up will necessarily be political.  But even with political will, it can’t happen without technology that’s <i>capable</i> of scaling, and <i>economically viable</i> at scale.</p>

<p>As technologists, that’s where we come in.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure" style="margin-bottom:-10px;">
<div class="figure-caption" style="margin-bottom:4px;">optimistic roadmap for 100% clean energy in U.S. by 2050, Mark Jacobson et al
<span class="cite"><a href="https://web.stanford.edu/group/efmh/jacobson/Articles/I/USStatesWWS.pdf">(source)</a></span></div>
<div class="script" data-script="svg 02-jacobson" style="width:440px;height:300px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="production-stuff"><a href="#production-stuff">The stuff around the thing</a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Many people seem to assume that breakthoughs in clean energy will come in the form of new generation technology — <a href="http://www.lockheedmartin.com/us/products/compact-fusion.html">fusion</a> <a href="http://news.mit.edu/2015/small-modular-efficient-fusion-plant-0810">reactors</a>, <a href="http://news.mit.edu/2013/thinner-solar-panels-0626">nanoscale solar cells</a>, that sort of thing.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/02-fusion.jpg" width="440" height="100">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Those will be good things to have!  But there’s more than enough power available to today’s solar cells and wind turbines — if only the <i>systems</i> were cheaper, simpler, and scalable. Here are a few examples of the kinds of projects I find interesting:</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 02-solar-land" style="width:440px;height:71px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://www.google.com/makani/">Makani</a> hoists its wind turbine to high altitudes with a flying wing instead of a tower.</p>

<blockquote>Makani’s energy kite actually operates on the same aerodynamic principles as a conventional wind turbine, but is able to replace tons of steel with lightweight electronics, advanced materials, and smart software. By using a flexible tether, energy kites eliminate <b>90% of the materials</b> used in conventional wind turbines, resulting in lower costs. <span class="cite"><a href="https://www.google.com/makani/faq/">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/02-makani.jpg" width="440" height="150">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://www.altaerosenergies.com/">Altaeros</a> uses a blimp.</p>

<blockquote>The Altaeros Buoyant Airborne Turbine reduces the second largest cost of wind energy – the installation and transport cost – by <b>up to 90 percent</b>, through a containerized deployment that does not require a tower, crane, or cement foundation. <span class="cite"><a href="http://www.altaerosenergies.com/value.html">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/02-altaeros.jpg" width="440" height="105">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://www.sunfolding.com/">Sunfolding</a> does solar tracking with pneumatically-actuated plastic soda bottles.</p>

<blockquote>Actuation and control are the highest cost components of today’s tracking systems. Together they account for nearly <b>50% of the tracking system cost</b>.  We replace both with our new approach to tracker design. <span class="cite"><a href="http://www.sunfolding.com/">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/02-sunfolding.jpg" width="440" height="130">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>These projects aren’t about better generators. They are about dramatically reducing the cost of the stuff <i>around</i> the generator.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Some of the best news of the last few years is the plunging cost of solar power.  It’s instructive to look at what exactly is <a href="http://cleantechnica.com/2015/01/29/solar-costs-will-fall-40-next-2-years-heres/">responsible for the drop</a>.  It’s partly cheaper solar panels, due to improved conversion efficiency and falling manufacturing costs.  But panels are now so cheap that they only make up 25% of the <a href="https://en.wikipedia.org/wiki/Balance_of_system">total system cost</a>.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption">levelized cost of solar photovoltaic power ($/MWh)
<span class="cite"><a href="http://rameznaam.com/2014/10/05/solar-wind-plunging-below-fossil-fuel-prices/">(source)</a></span></div>
<div class="script" data-script="svg 02-solar-price" style="width:440px;height:108px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The majority of the price drop is now due to better inverters, and better mounting racks, and better installation techniques, and better ways for solar companies to interact with customers.  There’s innovation everywhere, and you don’t need to be on the photovoltaic manufacturing line in order to play.</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 02-solarcost" style="width:440px;height:88px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The reason that these reductions in system cost are potentially so significant is the tipping point once solar and wind are consistently cheaper than fossil fuels and can be scaled up to meet demand.</p>

<p>My point here is that there are many ways of contributing toward innovation in the production of clean energy without going off and building a fusion reactor.  Look at the stuff around the things.<p>

<!-- left-column --></div></div><div class="row"><div class="column-left">


<h3 id="production-computation"><a href="#production-computation">Computation</a></h3>

<p>Even for something as physical as power generation, the right software can make a signficant contribution.  A few examples that come to mind:</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://www.kalyanv.org">Kalyan Veeramachaneni</a> et al at MIT used <a href="http://groups.csail.mit.edu/EVO-DesignOpt/groupWebSite/uploads/Main/IJCAI_sub_KV_AC_UM.pdf">modern probabilistic modeling</a> to <a href="https://news.mit.edu/2015/siting-wind-farms-quickly-cheaply-0717">dramatically improve</a> the process of estimating wind capacity at a location, calculating more accurate predictions in a fraction of the time.</p>

<blockquote>We talked with people in the wind industry, and we found that they were using a very, very simplistic mechanism to estimate the wind resource at a site. <span class="cite"><a href="https://news.mit.edu/2015/siting-wind-farms-quickly-cheaply-0717">(source)</a></span></blockquote>

<p>They didn’t invent a windmill; they invented an algorithm to determine where the windmill should go. It’s now a <a href="http://cardinalwind.com">startup</a>.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:-14px;margin-left:26px;">KL divergence (wrongness) of wind estimates from ground truth
<span class="cite"><a href="http://groups.csail.mit.edu/EVO-DesignOpt/groupWebSite/uploads/Site/Veeramachaneni_copula.pdf">(source)</a></span></div>
<img src="Images/02-veeramachaneni.png" width="417" height="210">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="https://en.wikipedia.org/wiki/John_Dabiri">John Dabiri</a>’s team at Caltech used aerodynamic analysis to <a href="http://www.caltech.edu/news/caltechs-unique-wind-projects-move-forward-39703">dramatically improve</a> the energy production and compactness of wind farms.  Their work computes the optimal placement of vertical turbines so they <a href="http://dabirilab.com/fieldlab/">reinforce each other</a> instead of interfering, making possible large arrays of small turbines.</p>

<blockquote>
This approach dramatically extends the reach of wind energy, as smaller wind turbines can be installed in many places that larger systems cannot, especially in built environments. ...
Favorable economics stem from an <b>orders-of-magnitude reduction in the number of components</b> in a new generation of simple, mass-manufacturable (even 3D-printable), vertical-axis wind turbines. <span class="cite"><a href="http://static1.squarespace.com/static/55885cf4e4b04e6344662d6a/t/5589cc47e4b09ddbc396cb89/1435094087643/DaGrKoMoPe_AIPCP15.pdf">(source)</a></span></blockquote>

<p>Again, they didn’t invent a new windmill; they used <a href="http://static1.squarespace.com/static/55885cf4e4b04e6344662d6a/t/5589ce85e4b06ad87a6166b3/1435094661559/WhLiDa_BB10.pdf">computational modeling</a> to make viable a much smaller and cheaper existing windmill.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:-14px;margin-left:26px;">footprint power density (watts extracted per square meter of land)
<span class="cite"><a href="http://static1.squarespace.com/static/55885cf4e4b04e6344662d6a/t/5589cba1e4b0e41fcfcabba7/1435093921809/Da_PT14.pdf">(source)</a></span></div>
<img src="Images/02-dabiri.png" width="440" height="236">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://www.google.com/makani">Makani</a> and <a href="http://www.sunfolding.com">Sunfolding</a> both sprung from Saul Griffith’s <a href="https://otherlab.com">Otherlab</a>, and much of Otherlab’s magic lies in their code.  A common theme is replacing physical material with dynamic control systems:</p>

<blockquote>[Makani’s kite’s] computer system uses GPS and other sensors along with thousands of real-time calculations to guide the kite to the flight path with the strongest and steadiest winds for maximum energy generation. <span class="cite"><a href="https://www.google.com/makani/technology/">(source)</a></span></blockquote>

<blockquote>
<span class="author">(Saul Griffith)</span> The really big themes I’d like to emphasize, because we need more people to join the club, so to speak, is the importance of being able to substitute a control system — sensors and computers — for actual materials...  We are actually now replacing atoms with bits. <span class="cite"><a href="https://www.youtube.com/watch?v=gyMowPAJwqo&t=12m35s">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/02-control-for-material.jpg" width="440" height="229">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>as well as creating new software tools for design and manufacturing:</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<blockquote><p>Griffith’s team had to write modeling software for the inflatables, because nobody had done anything like it before. But Otherlab creates its own software much of the time anyway. The 123D line of 3D modeling software offered by Autodesk grew out of one of his projects.</p>

<p>“We write all of our own tools, no matter what project we’re building,” Griffith says. “Pretty much anything that we’re doing requires some sort of design tool that didn’t exist before. In fact, the design tools that we write to do the projects that we’re doing are a sort of product in and of themselves.” <span class="cite"><a href="http://www.wired.com/2012/11/saul-griffith/">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption">123D Make</div>
<a href="http://www.123dapp.com/make"><img src="Images/02-123d-make.jpg" width="440" height="140"></a>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>My point here is that software isn’t just for drawing pixels and manipulating databases — it underlies a lot of the innovation even in physical technology.  More on this below.</p>


<!-- end chapter --></div></div></div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- energy moving -->

<div id="moving" class="toc"></div>
<h2>Moving Energy</h2>

<!-- begin chapter --><div class="chapter">
<!-- first left-column --><div class="row"><div class="column-left">

<p>I recently visited the <a href="http://www.caiso.com/">California ISO</a>, which orchestrates the power grid to match energy production with consumption in realtime.  The ISO exists because every megawatt that is generated at a power plant must be immediately consumed somewhere else.  There’s no buffer in the system, aside from a few reservoirs where they can occasionally <a href="https://en.wikipedia.org/wiki/Pumped-storage_hydroelectricity">pump water uphill</a>.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/03-caliso.jpg" width="440" height="197">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>So they’ve evolved a complex apparatus for <a href="http://www.caiso.com/Pages/TodaysOutlook.aspx">forecasting</a> energy demand, and sending realtime <a href="http://www.caiso.com/informed/Pages/EIMOverview/Default.aspx">price signals</a> to producers to make them adjust their output as needed.  This is becoming a <a href="http://cleantechnica.com/2014/07/21/utilities-cry-fowl-over-duck-chart-and-distributed-solar-powercrying-fowl-or-crying-wolf-open-season-on-the-utilitys-solar-duck-chart/">formidable challenge</a> as more and more intermittent (thus, unpredictable) renewables like solar and wind come online, and dirty and expensive <a href="https://en.wikipedia.org/wiki/Peaking_power_plant">peaker plants</a> have to be ramped up or down on a moment’s notice to balance them out.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:5px;">California ISO supply and demand in gigawatts, on Oct 22, 2015
<span class="cite"><a href="Notes/03-demand-curve.html">(source)</a></span></div>
<div class="script" data-script="svg 03-demand-curve" style="width:440px;height:189px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Everything about today’s power grid, from this centralized control to the <a href="https://en.wikipedia.org/wiki/Electrical_grid#Aging_Infrastructure">aging machinery</a> performing transmission and distribution, is not suitable for clean energy.  The power grid was designed to take input from a handful of tightly-regulated power plants <a href="http://charming.awardspace.com/powergen/powergen.html">running in synchrony</a>, not millions of solar roofs.  And it was designed for power plants that were <a href="https://en.wikipedia.org/wiki/Base_load_power_plant">always available and predictable</a>, not intermittent sources like the sun and wind.</p>

<blockquote>
If everyone in Los Angeles put solar panels on their roofs, plugged electric cars into their garages and used smart power-meters today, something interesting would happen.  The electric grid would collapse. <span class="cite"><a href="http://newsroom.ucla.edu/stories/building-the-smart-grid-151474">(source)</a></span></blockquote>

<p>In order for clean energy to work, it needs to get from where and when it is generated, to where and when it needed.  The “where” and “when” call for networking and storage, respectively.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:6px;">schematic of power grid in 1935, and also now <span class="cite"><a href="https://power2switch.com/blog/how-electricity-grew-up-a-brief-history-of-the-electrical-grid/">(source)</a></span></div>
<div class="script" data-script="svg 03-grid-schematic" style="width:440px;height:90px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="moving-networking"><a href="#moving-networking">Energy networking <span>(moving energy in space)</span></a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The key idea that made the internet possible was the move from centralized <a href="https://en.wikipedia.org/wiki/Circuit_switching">circuit-switched</a> networks to distributed <a href="https://en.wikipedia.org/wiki/Packet_switching">packet-switching</a> protocols, where data could “find its way” from sender to receiver.</p>

<p>Now it’s energy that needs to <a href="http://morethansmart.org/">find its way</a>.</p>

<blockquote><p>The power network... will undergo the same kind of architectural transformation in the next decades that computing and the communication network has gone through in the last two.</p>
</blockquote>

<!-- right-column --></div><div class="column-right">

<img style="margin-top:-20px;" src="Images/03-arpanet.png" width="440" height="185">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<blockquote><p>We envision a future network with hundreds of millions of active endpoints. These are not merely passive loads as are most endpoints today, but endpoints that may generate, sense, compute, communicate, and actuate. They will create both a severe risk and a tremendous opportunity: an interconnected system of hundreds of millions of distributed energy resources (DERs) introducing rapid, large, and random fluctuations in power supply and demand...</p>
<p>As infrastructure deployment progresses, the new bottleneck will be the need for <b>overarching frameworks, foundational theories, and practical algorithms</b> to manage a fully [data-centric] power network. <span class="cite"><a href="http://smart.caltech.edu">(source)</a></span></p>
</blockquote>

<p>This is an <a href="http://smart.caltech.edu">algorithms problem</a>!  It’s TCP/IP for energy.  Think of these <a href="http://smart.caltech.edu/publications-0.shtml">algorithms</a> as hybrids of distributed networking protocols and financial trading algorithms — they are <a href="http://smart.caltech.edu/papers/zeroduality.pdf">routing energy</a> as well as <a href="http://smart.caltech.edu/papers/marketmodels.pdf">participating in a market</a>.</p>

<!-- right-column --></div><div class="column-right">

<a href="http://morethansmart.org/programs/more-than-smart/"><img src="Images/03-more-than-smart.jpg" width="440" height="220"></a>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>TCP/IP spawned quite an <a href="https://en.wikipedia.org/wiki/Outline_of_the_Internet">industry of infrastructure and applications</a>.  It’s likely that something similar will happen as the <a href="https://www.smartgrid.gov/the_smart_grid/smart_grid.html">smart grid</a> gets underway.  One DOE-funded project attempting to provide the infrastructure for such an industry is <a href="http://transactionalnetwork.pnnl.gov/volttron.stm">VOLTTRON</a>, an “Intelligent Agent Platform for the Smart Grid”.

<blockquote>
<p>VOLTTRON is an innovative distributed control and sensing software platform. Its source code has been released, making it possible for researchers and others to use this tool to build applications for more efficiently managing energy use among appliances and devices, including heating, ventilation and air conditioning (HVAC) systems, lighting, electric vehicles and others. <span class="cite"><a href="http://gridoptics.pnnl.gov/VOLTTRON/">(source)</a></span></p></blockquote>

<blockquote>
<p>VOLTTRON is not an application such as demand response – demand response can be implemented as an application on top of VOLTTRON.</p>
<p>VOLTTRON is open, flexible and modular, and already benefits from community support and development. <span class="cite"><a href="http://transactionalnetwork.pnnl.gov/volttron.stm">(source)</a></span></p>
</blockquote>

<p>Protocols for <a href="https://en.wikipedia.org/wiki/Internet_protocol_suite">moving</a> <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol">data</a> <a href="https://en.wikipedia.org/wiki/BitTorrent">around</a> were the big thing for a few decades.  Then it was <a href="https://bitcoin.org">moving</a> <a href="https://www.stellar.org">money</a> <a href="https://stripe.com">around</a>.  The next big thing will be moving energy around.</p>

<!-- right-column --></div><div class="column-right">

<a href="https://github.com/VOLTTRON/volttron"><img src="Images/04-volttron-github.png" width="440" height="432"></a>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="moving-storage"><a href="#moving-storage">Energy storage <span>(moving energy in time)</span></a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Relying on sun and wind is only possible if we can store up their energy for when it’s not sunny or windy.  Many people assume that we’ll “just use batteries”, but the scale is off by a few orders of magnitude. All the batteries on earth can store <a class="no-preview" href="Notes/03-all-the-batteries.txt">less than ten minutes</a> of the world’s energy. At <a href="http://www.luxresearchinc.com/news-and-events/press-releases/read/energy-storage-market-rises-50-billion-2020-amid-dramatic">currently anticipated growth rates</a>, we wouldn’t have the batteries we need <a href="refs/DanielleFong-GrowthRateRequiredInEnergyStorage.pdf">for eighty years</a>.</p>

<p><a href="https://en.wikipedia.org/wiki/Grid_energy_storage">Grid-scale energy storage</a> is perhaps the most critical technology problem in clean energy. When I visited the <a href="http://www.caiso.com/">ISO</a>, the operator was just about <a href="http://www.caiso.com/Documents/ISOStoragePilotProjects-AdvancingSmarterGrid.pdf">imploring</a> us to invent better energy storage technologies, because they would change the game entirely.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:5px;">actual and required battery growth rates (power in terawatts, log scale)
    <span class="cite"><a href="refs/DanielleFong-GrowthRateRequiredInEnergyStorage.pdf">(source)</a></span></div>
<div class="script" data-script="svg 03-battery-growth" style="width:440px;height:182px;"></div>
</div>

<!-- close row --></div></div>

<div class="grid-3" data-preview-container="storage-preview-container">
<div class="grid-3-item">
    <img src="Images/03-tesla.jpg" width="300" height="230">
    <p>Tesla recently announced their <a href="http://www.teslamotors.com/powerwall">home battery initiative</a>, and a <a href="http://www.teslamotors.com/gigafactory">Gigafactory</a> to produce them.</p>

</div><div class="grid-3-item">

<img src="Images/03-lightsail.jpg" width="300" height="230">
<p> My friend Danielle Fong started <a href="http://www.lightsail.com/">LightSail Energy</a> to store energy by compressing air with an engine.</p>

</div><div class="grid-3-item">

<img src="Images/03-storage.jpg" width="300" height="230">
<p>There are various companies pursuing variations on batteries, compressors, flywheels, thermal storage, water pumps, <a href="https://en.wikipedia.org/wiki/List_of_energy_storage_projects">and more</a>.</p>
</div>
</div>

<!-- first left-column --><div class="row"><div class="column-left">

<div id="storage-preview-container"></div>

<p>Particularly charming is <a href="http://www.aresnorthamerica.com/">Advanced Rail Energy Storage</a>, whose <a href="http://www.aresnorthamerica.com/grid-scale-energy-storage">proposal</a> is</p>

<blockquote>using lower-cost power to drive a train uphill and then let the train roll downhill to produce power when market prices are high. <span class="cite"><a href="http://www.aresnorthamerica.com/article/4875-advanced-rail-energy-storage-using-trains-to-store-power">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right" style="margin-bottom:14px;">

<img src="Images/03-ares.jpg" width="440" height="153">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>There’s also something delightful about the image of <a href="http://www.calmac.com">CALMAC</a>’s <a href="http://www.calmac.com/calmac-products-and-specifications">IceBank®</a>, <a href="http://ice-energy.com">Ice Energy</a>’s <a href="http://ice-energy.com/technology/">Ice Bear®</a>, and <a href="http://www.axiomexergy.com">Axiom</a>’s <a href="http://www.axiomexergy.com/#!the-refrigeration-battery-/c1z06">Refrigeration Battery™</a> battling it out in the arena of building-sized ice makers.</p>

<blockquote>IceBank is an air-conditioning solution that makes ice at night [when energy demand is low] to cool buildings during the day. <span class="cite"><a href="http://www.calmac.com">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right" style="margin-bottom:10px;">

<img src="Images/03-ice.jpg" width="440" height="174">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>All this may make energy storage seem like a competitive space.  But the reality is that these companies aren’t competing with each other so much as they are competing with <a href="https://en.wikipedia.org/wiki/Peaking_power_plant">peaker plants</a> and cheap fossil fuels.  An energy storage startup can be in the strange position of continually adjusting their product and strategy in response to fluctuations in fossil fuel prices.</p>

<p>But as in the case of energy production, there should be a tipping point if storing and reclaiming renewable energy can be made decisively cheaper than generating it from natural gas, and can be scaled up to meet demand.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<a href="http://www.lightsail.com/opportunity/"><img src="Images/03-equation.png" width="440" height="157"></a>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The core technologies in energy storage tend to be physics-based, but software plays essential roles in the form of design tools, simulation tools, and control systems.  My favorite example is the inexplicably gorgeous <a href="https://www.materialsproject.org">Materials Project</a>, a database and visualization tool for material properties, funded by the Department of Energy’s <a href="http://energy.gov/eere/vehicles/vehicle-technologies-office">Vehicle Technologies Program</a> to help <a href="http://energy.gov/sites/prod/files/2014/03/f9/vtpn07_es_howell_2012_o.pdf">invent better batteries</a>.
  
<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/03-materials.jpg" width="440" height="226">
</div>


<!-- end chapter --></div></div></div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- energy consumption -->

<div id="consumption" class="toc"></div>
<h2>Consuming Energy</h2>

<!-- begin chapter --><div class="chapter">

<div class="script figure" data-script="chart 04-sectors" style="width:940px;height:71px;margin-bottom:20px;"></div>

<div style="position:relative;width:940px;height:200px;">
    <div class="figure inline script" data-script="chart 04-transportation" style="width:233px;height:119px;"></div>
    <div class="figure inline script" data-script="chart 04-manufacturing" style="width:296px;height:171px;"></div>
    <div class="figure inline script" data-script="chart 04-residential" style="width:183px;height:93px;"></div>
    <div class="figure inline script" data-script="chart 04-commercial" style="width:155px;height:158px;"></div>
</div>

<!-- first left-column --><div class="row"><div class="column-left">

<h3 id="consumption-transportation"><a href="#consumption-transportation">Transportation <span>(consuming what?)</span></a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>To the right is how the U.S. currently generates energy.  The most conspicuous <a href="https://flowcharts.llnl.gov/commodities/carbon">source of carbon emissions</a> is the thick green bar from “petroleum” to “transportation”.  We need to erase that.</p>

<p>While we’re at it, we also ought to erase the thick grey bar from “transportation” to “wasted”.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure" style="margin-top:-44px;position:relative;">
    <img src="Images/04-sankey.png" width="440" height="198">
    <div class="script" data-script="svg 04-sankey" style="position:absolute;left:0;top:0;width:440px;height:198px;"></div>
    <span class="cite" style="position:absolute;left:86px;top:-6px;"><a href="https://flowcharts.llnl.gov">(source)</a></span>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Passenger vehicles account for the majority of transportation-related greenhouse gas emissions. There are a number of emerging ways to reduce this impact.</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 04-transportation-CO2" style="width:440px;height:97px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<div class="indent">
<p><b>Electric vehicles</b> are inevitable.  Today, powering a car from the grid might not be much cleaner than burning gasoline.  But once the grid cleans up, not only will electric cars be cleaner than gas cars, they may be <a href="http://www.templetons.com/brad/robocars/transit-ends.html">more efficient than mass transit</a>.</p>
</div>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 04-ev-grid" style="width:440px;height:97px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">
 
<div class="indent">
<p><b>New kinds of powered vehicles</b> are becoming possible which are more nimble and efficient than cars.</p>
</div>

<!-- close row --></div></div>

<div style="margin-top:-15px;margin-bottom:5px;text-align:center;"><img src="Images/04-evs-row.png" width="728" height="140"></div>

<!-- first left-column --><div class="row"><div class="column-left">

<div class="indent">
<p>Most trips people take are fairly short. It’s not inconceivable that new vehicles could replace cars for most trips if the technology, design, and marketing are right, and the proper <a href="http://www.wired.com/2015/06/copenhagenize-worlds-most-bike-friendly-cities/">infrastructure</a> and laws are in place.  And you don’t need to start a <a href="http://www.teslamotors.com">car company</a> to <a href="https://www.faradaybikes.com">work</a> <a href="http://boostedboards.com/">on</a> <a href="http://ecorecoscooter.com/">them</a>.</p>
</div>

<div class="indent">
<p><b>Coordinated autonomous vehicles</b> could lead to very different ways of moving around <a href="http://www.templetons.com/brad/robocars/whistlecar.html">people</a> and <a href="http://www.templetons.com/brad/robocars/deliverbots.html">deliveries</a>. This is basically mobile robotics on a big scale.  And again, you don’t necessarily need to go work for a <a href="http://www.google.com/selfdrivingcar/">car company</a> in order to make <a href="http://www.starship.xyz">interesting things</a> here.</p>
</div>

<!-- right-column --></div><div class="column-right">

<div class="script figure floaty" data-script="chart 04-trip-distribution" style="width:440px;height:201px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<div class="indent">
<p><b>Reducing the need</b> for personal transportation via <a href="https://en.wikipedia.org/wiki/Car-free_movement">urban design</a>.  Among other reasons, this is important to counter the likely tendency of autonomous cars to <a href="https://askwonder.com/research-network/response/55f4ea68117aa6240064cdbe">increase urban sprawl</a>, which has been <a href="http://siteresources.worldbank.org/INTURBANDEVELOPMENT/Resources/336387-1342044185050/8756911-1342044630817/V2Chap09.pdf">strongly correlated with emissions</a>.</p>
</div>

<!-- right-column --></div><div class="column-right">

<img src="Images/04-ecocity.jpg" width="440" height="80">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Similar opportunities apply to <a href="https://en.wikipedia.org/wiki/Fleet_vehicle">fleet vehicles</a>.  One of the <a href="http://www.fool.com/investing/general/2015/05/17/why-is-this-tesla-motors-co-founder-putting-jet-tu.aspx">cofounders of Tesla</a> is now in the business of <a href="http://www.wrightspeed.com">electrifying Fedex vans and garbage trucks</a>.  Long-haul trucks are more of a challenge, but there’s room for improvement in <a href="http://www.actexpo.com/expohall">fuels</a>, <a href="http://www.truckingefficiency.org">vehicle design</a>, and <a href="http://www.grahampeacedesignmail.com/cwr/cwr2012_trucking_finall_download_singles.pdf">logistics</a>.</p>

<p>As for airplanes, people might just have to <a href="http://www.withouthotair.com/c5/page_35.shtml">fly less</a>.  This will require better tools for remote collaboration, or in Saul Griffith’s words, “<a href="http://longnow.org/seminars/02015/sep/21/infrastructure-and-climate-change/#reader_wrapper">Make video conferencing not suck.</a>”</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 04-truck-emissions" style="width:440px;height:84px;"></div>


<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="consumption-coordination"><a href="#consumption-coordination">Coordination <span>(consuming when?)</span></a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Many home appliances that consume significant electricity — air conditioner, water heater, clothes dryer, electric vehicle charger — have some tolerance in when they actually need to run.  You don’t care exactly when your electric car is charging as long as it’s charged in the morning, and you don’t care exactly when your water heater is heating, as long as the tank stays hot.</p>

<p>If your water heater could talk to your neighbor’s water heater and agree to avoid heating water at the same time, it would flatten out the demand curve, and help avoid the ups and downs that must be serviced by <a href="https://en.wikipedia.org/wiki/Peaking_power_plant">peaker plants</a>.  The water heater could also work aggressively when solar power was plentiful and hold back when clouds went by, to match the intermittency of renewables and require less energy storage.</p>

<!-- right-column --></div><div class="column-right">

<div class="script figure" data-script="chart 04-residential-electricity" style="width:440px;height:136px;"></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The <a href="http://www.rmi.org">Rocky Mountain Institute</a> calls this “<a href="http://www.rmi.org/electricity_demand_flexibility">demand flexibility</a>”, and imagines appliances coordinated through price signals.</p>

<blockquote>
Demand flexibility uses communication and control technology to shift electricity use across hours of the day while delivering end-use services at the same or better quality but lower cost. It does this by applying automatic control to reshape a customer’s demand profile continuously in ways that either are invisible to or minimally affect the customer. <span class="cite"><a href="http://www.rmi.org/cms/Download.aspx?id=11692&file=RMI-TheEconomicsofDemandFlexibilityExecSummary.pdf">(source)</a></span>
</blockquote>

<p>This sort of coordination is a <a href="https://www.youtube.com/watch?v=IBwtCjiBvR0&t=1m36s">goal</a> of many of the “smart grid” proposals.</p>


<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:6px;">example of load-shifting in response to price (usage in kW)
    <span class="cite"><a href="http://www.rmi.org/cms/Download.aspx?id=11693&file=RMI-TheEconomicsofDemandFlexibilityFullReport.pdf">(source)</a></span></div>
<div class="script" data-script="svg 04-demand-flexibility" style="width:440px;height:156px;"></div>
</div>


<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="consumption-efficiency"><a href="#consumption-efficiency">Efficiency <span>(consuming how much?)</span></a></h3>

<!-- close row --></div></div>

<div class="grid-3" data-preview-container="efficiency-preview-container">
<div class="grid-3-item">
    <div class="figure">
    <div class="figure-caption" style="margin-bottom:4px;">per capita electricity use in MWh
        <span class="cite"><a href="http://www.arb.ca.gov/research/seminars/chu/chu.pdf">(source)</a></span></div>
    <div class="script" data-script="svg 04-per-capita" style="width:314px;height:202px;margin-left:-14px; margin-bottom:10px;"></div>
    </div>
    <p>In the 1970s, efficiency pioneer <a href="http://eetd.lbl.gov/about-us/arthur-h-rosenfeld">Art Rosenfeld</a> instigated an <a href="http://www.energy.ca.gov/commissioners/rosenfeld_docs/2000-10_ROSENFELD_AUTOBIO.PDF">unprecedented program of energy saving</a>, literally halting the growth of per-capita electricity consumption in California.</p>

</div><div class="grid-3-item">

    <div class="figure">
    <div class="figure-caption" style="margin-bottom:4px;">energy savings in California in TWh
        <span class="cite"><a href="http://www.arb.ca.gov/research/seminars/chu/chu.pdf">(source)</a></span></div>
    <div class="script" data-script="svg 04-utility-profits" style="width:314px;height:202px;margin-left:-14px; margin-bottom:10px;"></div>
    </div>
    <p>A lot of important technology came out of his lab, such as the <a href="https://en.wikipedia.org/wiki/Electrical_ballast">ballasts</a> that made <a href="https://en.wikipedia.org/wiki/Compact_fluorescent_lamp">compact florescent lamps</a> viable, but his two biggest influences were regulatory.  Half the energy savings in California came from <a href="https://eaei.lbl.gov/sites/all/files/sharing-the-savings-to-promote-energy-efficiency.pdf">adjusting the profit structure</a> of power utilities so they could be profitable selling <i>less</i> power.</p>

</div><div class="grid-3-item">

    <div class="figure">
    <div class="figure-caption" style="margin-bottom:4px;">energy consumption of new U.S. refrigerators in MWh/yr
        <span class="cite"><a href="http://www.energy.ca.gov/commissioners/rosenfeld_docs/2000-10_ROSENFELD_AUTOBIO.PDF">(source)</a></span></div>
    <div class="script" data-script="svg 04-refrigerators" style="width:314px;height:202px;margin-left:-14px; margin-bottom:10px;"></div>
    </div>
    <p>The other half came from mandating energy usage standards for <a href="http://www.energy.ca.gov/title24/2013standards/">buildings</a> and <a href="http://energy.gov/eere/buildings/appliance-and-equipment-standards-program">appliances</a>.  These standards, as well as more recent voluntary programs such as <a href="https://www.energystar.gov">Energy Star</a>, forced companies to compete on efficiency.  This drove innovation (and even <a href="http://iopscience.iop.org/article/10.1088/1748-9326/9/11/114010/pdf">reduced cost!</a>) far more than simple consumer preference.</p></div><!-- grid-3-item -->

</div><!-- grid-3 -->

<!-- first left-column --><div class="row"><div class="column-left">

<div id="efficiency-preview-container"></div>

<p>Building standards are a particularly interesting case here, because they were, and are, intimately tied to software.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<blockquote>
<p><span class="author">(Art Rosenfeld)</span> [In 1975] the CEC’s draft “Title 24” residential building standard proposed to limit window area to 15% of wall area, without distinguishing among north, south, east, and west. Indeed I don’t think the standard even mentioned the sun!</p>
<p>I contacted the CEC and discovered why they thought that windows wasted heat in winter and “coolth” in summer. The CEC staff had a choice of only two public-domain computer programs, the “Post Office” program, which was user hostile... and a newer program [NBSLD]... They chose NBSLD, but unfortunately had run it in a “fixed-thermostat” mode that kept the conditioned space at 72°F (22°C) all year...</p>
<p>NBSLD’s author, Tamami Kusuda, had written a “floating-temperature” option, but it was more complicated and still had bugs, and neither Tamami nor anybody at CEC could get it to work satisfactorily. No wonder the CEC concluded that windows wasted energy!</p>
<p>I decided that California needed two programs for energy analysis in buildings: first and immediately, a simple program for the design of single-family dwellings and, second and later, a comprehensive program for the design of large buildings, with a floating-indoor-temperature option and the ability to simulate HVAC distribution systems... <span class="cite"><a id="foo" href="http://www.energy.ca.gov/commissioners/rosenfeld_docs/2000-10_ROSENFELD_AUTOBIO.PDF">(source)</a></span></p>
</blockquote>

<!-- right-column --></div><div class="column-right">

<a href="http://www.energy.ca.gov/commissioners/rosenfeld_docs/2000-10_ROSENFELD_AUTOBIO.PDF"><img src="Images/04-rosenfeld-bio-sm.jpg" width="350" height="400"></a>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Rosenfeld’s energy-modeling software (which became <a href="http://doe2.com/doe2/">DOE-2</a>, then <a href="https://energyplus.net">EnergyPlus</a>) was quickly and widely adopted for calculating and specifying building performance standards.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Not only does <a href="https://simulationresearch.lbl.gov">energy simulation software</a> still <a href="http://www.energy.ca.gov/title24/2013standards/2013_computer_prog_list.html">drive building standards</a>, energy analysis tools such as <a href="https://gbs.autodesk.com/GBS/">Green Building Studio</a> and <a href="https://www.openstudio.net">OpenStudio</a> are now an integral part of the building design process.  Particularly interesting are tools such as <a href="http://sefaira.com">Sefaira</a> and <a href="https://flux.io/">Flux</a>, which give the designer immediate feedback on energy performance as they <a href="https://www.youtube.com/watch?v=F7snroYkomY&t=4m40s">adjust building parameters in realtime</a>.</p>

<!-- right-column --></div><div class="column-right">

<div class="inline" style="margin-right:10px;"><div class="figure-caption">Sefaira</div><a href="http://sefaira.com/"><img src="Images/04-sefaira.jpg" width="215" height="136"></a></div><div class="inline"><div class="figure-caption">Flux</div><a href="https://flux.io/"><img src="Images/04-flux.jpg" width="215" height="136"></a></div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>If efficiency incentives and tools have been effective for utilities, manufacturers, and designers, what about for end users?  One concern I’ve always had is that most people have <i>no idea</i> where their energy goes, so any attempt to conserve is like optimizing a program without a profiler.</p>

<!-- close row --></div></div>

<div class="grid-4" data-preview-container="efficiency-analytics-preview-container">
<div class="grid-4-item">
    <img src="Images/04-feedback-killawatt.jpg" width="227" height="118">
    <p>Efficiency through analytics has motivated a lot of projects, from the humble and niche <a href="http://www.p3international.com/products/p4400.html">Kill-A-Watt</a>,</p>

</div><div class="grid-4-item">
    <img src="Images/04-feedback-google.jpg" width="227" height="118">
    <p> to the characteristically <a href="http://arstechnica.com/information-technology/2011/07/microsoft-follows-googles-lead-cancels-hohm-energy-service/">short-lived</a> <a href="https://en.wikipedia.org/wiki/Google_PowerMeter">Google PowerMeter</a> and <a href="https://en.wikipedia.org/wiki/Hohm">Microsoft Hohm</a> services.</p>

</div><div class="grid-4-item">
    <img src="Images/04-feedback-saver.jpg" width="227" height="118">
    <p>There are online energy calculators, such as <a href="http://www.lbl.gov">Berkeley Lab</a>’s <a href="http://homeenergysaver.lbl.gov/consumer/">Home Energy Saver</a>,</p>

</div><div class="grid-4-item">
    <img src="Images/04-feedback-dashboard.jpg" width="227" height="118">
    <p>and <a href="http://www.deckmonitoring.com/building-efficiency/building-efficiency-for-commercial.html">energy dashboards</a> are appearing in commercial and institutional buildings.</p>

</div></div>


<!-- first left-column --><div class="row"><div class="column-left">

<div id="efficiency-analytics-preview-container"></div>

<p>Many of these projects are <a href="http://www.greentechmedia.com/articles/read/Why-Your-Energy-Dashboard-May-be-Doomed-to-Fail">unsuccessful</a> and possibly only marginally effective.  I don’t think this means that efficiency feedback will always be unsuccessful — just that it needs to be done <i>well,</i> it needs to be <i>actionable,</i> and most importantly, it needs to be targeted at people with the <i>motivation and leverage</i> to take significant action.</p>

<p>Individual consumers and homeowners might not be the best targets.  A more promising audience is people who manage large-scale systems and services.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>For example, garbage collection.  Garbage trucks stop-and-go down every street, in every city, at <a href="http://www.cert.ucr.edu/events/pems2014/liveagenda/25sandhu.pdf">3 miles per gallon</a>.  The startup <a href="http://www.enevo.com">Enevo</a> makes sensors which trash collectors install in dumpsters, and provides logistics software that plans an optimal collection route each day.  By only picking up full bins,  they cut fuel consumption in half.</p>

<p>Enevo works at the system level, not consumer level.  There are fewer customers at system-level, but those customers have the <i>motivation and leverage</i> to implement heavy efficiency improvements.</p>

<!-- right-column --></div><div class="column-right">

<a href="http://www.enevo.com"><img src="Images/04-enevo.jpg" width="318" height="180"></a>

<!-- end chapter --></div></div></div>


<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- tools -->

<div id="tools" class="toc"></div>
<h2>Tools for Scientists &amp; Engineers</h2>

<!-- begin chapter --><div class="chapter">
<!-- first left-column --><div class="row"><div class="column-left">

<p>You won’t find programming languages mentioned in an <a href="http://www.ipcc.ch">IPCC</a> report.  Their influence is indirect; they get taken for granted.  But I feel that technical tools are of overwhelming importance, and completely under the radar of most people working to address climate change.</p>


<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="tools-technical"><a href="#tools-technical">Languages for technical computing</a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>I was hanging out with climate scientists while working on <a href="http://pushpoppress.com/ourchoice/">Al Gore’s book</a>, and they mostly did their thing in <a href="https://en.wikipedia.org/wiki/R_(programming_language)">R</a>.  This is typical; most statistical research is <a href="http://blog.kaggle.com/2011/11/27/kagglers-favorite-tools/">done in R</a>.  The language seems to inspire a level of vitriol that’s impressive even by programmers’ standards.  Even R’s advocates always seem <a href="https://www.youtube.com/watch?v=6S9r_YbqHy8">sort of apologetic</a>.</p>

<blockquote>
Using R is a bit akin to smoking. The beginning is difficult, one may get headaches and even gag the first few times. But in the long run, it becomes pleasurable and even addictive. Yet, deep down, for those willing to be honest, there is something not fully healthy in it. <span class="cite"><a href="http://www.johndcook.com/blog/2012/02/29/comparing-r-to-smoking/">(source)</a></span></blockquote>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<a href="Images/05-r-big.jpg"><img src="Images/05-r.png" width="300" height="200"></a>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Complementary to R is <a href="https://en.wikipedia.org/wiki/MATLAB">Matlab</a>, the primary language for numerical computing in many scientific and engineering fields.  It’s ubiquitous. Matlab has been described as “the PHP of scientific computing”.</p>

<blockquote>
MATLAB is not good. <a href="https://archive.is/GLnbp">Do not use it.</a> <span class="cite"><a href="https://archive.is/GLnbp">(source)</a></span></blockquote>

<p>R and Matlab are both forty years old, weighed down with forty years of cruft and bad design decisions.  Scientists and engineers use them because they are the vernacular, and there are no better alternatives.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<a href="Images/05-matlab-big.png"><img src="Images/05-matlab.png" width="440" height="144"></a>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>Here’s an opinion you might not hear much — I feel that one effective approach to addressing climate change is contributing to the development of <a href="http://julialang.org/">Julia</a>.  Julia is a modern technical language, intended to replace Matlab, R, SciPy, and C++ on the scientific workbench. It’s <a href="http://danluu.com/julialang">immature</a> right now, but it has beautiful <a href="http://arxiv.org/abs/1411.1607">foundations</a>, enthusiastic users, and a lot of potential.</p>

<p>I say this despite the fact that my own work has been in much the opposite direction as Julia.  Julia inherits the textual interaction of classic Matlab, SciPy and other children of the teletype — source code and command lines.</p>

<p>The goal of my own research has been tools where scientists see what they’re doing in realtime, with immediate visual feedback and interactive exploration.  I deeply believe that a sea change in invention and discovery is possible, once technologists are working in environments designed around:</p>

<!-- right-column --></div><div class="column-right">

<div class="figure" style="margin-top:6px;">
<a href="https://github.com/JuliaLang/julia/blob/master/base/dsp.jl"><img src="Images/05-julia.png" width="353" height="192"></a>
</div>

<!-- close row --></div></div>

<div class="dynamic-tools no-preview" data-preview-container="dynamic-tools-preview-container"><div class="dynamic-tools-item">

    <div class="figure-caption">Interactive Exploration of a Dynamical System</div>
    <a href="https://vimeo.com/23839605"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-0.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-0.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-0.webm" type="video/webm">
    </video></div></a>
    <p>ubiquitous visualization and in-context manipulation of the system being studied;</p>

</div><div class="dynamic-tools-item">

    <div class="figure-caption">Up and Down the Ladder of Abstraction</div>
    <a href="http://worrydream.com/LadderOfAbstraction/"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-1.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-1.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-1.webm" type="video/webm">
    </video></div></a>
    <p>actively exploring system behavior across multiple levels of abstraction in parallel;</p>

</div><div class="dynamic-tools-item">

    <div class="figure-caption">Multitrack Signal Processing</div>
    <a href="http://worrydream.com/MediaForThinkingTheUnthinkable/"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-2.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-2.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-2.webm" type="video/webm">
    </video></div></a>
    <p>visually investigating system behavior by transforming, measuring, searching, abstracting;</p>

</div></div>

<div class="dynamic-tools no-preview" data-preview-container="dynamic-tools-preview-container"><div class="dynamic-tools-item">

    <div class="figure-caption">Inventing on Principle</div>
    <a href="https://vimeo.com/36579366"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-3.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-3.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-3.webm" type="video/webm">
    </video></div></a>
    <p>seeing the values of all system variables, all at once, in context;</p>

</div><div class="dynamic-tools-item">

    <div class="figure-caption">Media for Thinking the Unthinkable</div>
    <a href="http://worrydream.com/MediaForThinkingTheUnthinkable/"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-4.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-4.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-4.webm" type="video/webm">
    </video></div></a>
    <p>dynamic notations that embed simulation, and show the effects of parameter changes;</p>

</div><div class="dynamic-tools-item">

    <div class="figure-caption">Drawing Dynamic Visualizations</div>
    <a href="https://vimeo.com/66085662"><div class="dynamic-tools-thumbnail"><div class="border"></div><img src="Images/05-dynamic-5.png" width="306" height="170"><video loop width="306" height="170">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-5.mov" type="video/mp4">
        <source src="https://s3.amazonaws.com/worrydream.com/ClimateChange/Video/05-dynamic-5.webm" type="video/webm">
    </video></div></a>
    <p>visually improvising special-purpose dynamic visualizations as needed.</p>

</div></div>


<!-- first left-column --><div class="row"><div class="column-left">

<div id="dynamic-tools-preview-container"></div>

<p>Obviously I think this approach is important, and I urge you to pursue it if it speaks to you.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>At the same time, I’m also happy to endorse Julia because, well, it’s just about the only example of well-grounded academic research in technical computing.  <i>It’s the craziest thing.</i>  I’ve been following the programming language community for a decade, I’ve spoken at <a href="http://splashcon.org">SPLASH</a> and <a href="http://popl.mpi-sws.org">POPL</a> and <a href="http://www.thestrangeloop.com">Strange Loop</a>, and it’s only slightly an unfair generalization to say that almost every programming language researcher is working on</p>

<div class="indent"><p>
(a) languages and methods for software developers,<br>
(b) languages for novices or end-users,<br>
(c) implementation of compilers or runtimes, or<br>
(d) theoretical considerations, often of type systems.
</p></div>

<p>The very concept of a “programming language” originated with <a href="https://en.wikipedia.org/wiki/Fortran">languages for scientists</a> — now such languages aren’t even part of the discussion!  Yet they remain the tools by which humanity understands the world and builds a better one.</p>

<p>If we can provide our climate scientists and energy engineers with a civilized computing environment, I believe it will make a very significant difference.  But not one that is easily visible or measured!</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption">(a) sampling of “languages and methods for software developers” at SPLASH 2015
<span class="cite"><a href="http://2015.splashcon.org/program/program-splash2015">(source)</a></span></div>
<div class="splash-list">
Rust: Idioms and Design Patterns<br>
Functional Reactive Programming with nothing but Promises<br>
Proposal for an Object-Oriented Multiple Dispatch Mechanism<br>
Logical Reactive Programming<br>
Real-Time Deadlines in Functional-Reactive Programming<br>
Beyond Bash: Shell scripting in a statically-typed, object-oriented language<br>
</div></div>

<div class="figure">
<div class="figure-caption">(b) sampling of “languages for novices or end-users” at SPLASH 2015
<span class="cite"><a href="http://2015.splashcon.org/program/program-splash2015">(source)</a></span></div>
<div class="splash-list">
The Spreadsheet Paradigm: A Basis for Powerful and Accessible Programming<br>
Model, Execute, Deploy: Answering the Hard Questions about End-user Programming<br>
Language-Oriented Business Applications: Helping End Users become Programmers<br>
ActiveSheets: Stream Processing with a Spreadsheet<br>
The Gamma: Programming tools for data journalism<br>
An end-user programming environment that’s cell-based and copy/paste friendly<br>
</div></div>

<div class="figure">
<div class="figure-caption">(c) sampling of “implementation of compilers or runtimes” at SPLASH 2015
<span class="cite"><a href="http://2015.splashcon.org/program/program-splash2015">(source)</a></span></div>
<div class="splash-list">
Akka.js: Towards a portable actor runtime environment<br>
CLOP: A multi-stage compiler to seamlessly embed heterogeneous code<br>
Language Independent Storage Strategies for Tracing JIT based VMs<br>
Java-to-JavaScript Translation via Structured Control Flow Reconstruction of Compiler IR<br>
Runtime Pointer Disambiguation<br>
Optimizing Hash-Array Mapped Tries for Fast and Lean Immutable JVM Collections<br>
</div></div>

<div class="figure">
<div class="figure-caption">(d) sampling of “theoretical considerations” at SPLASH 2015
<span class="cite"><a href="http://2015.splashcon.org/program/program-splash2015">(source)</a></span></div>
<div class="splash-list" style="margin-bottom:0;">
A Formal Foundation for Trace-Based JIT Compilers<br>
A Formalization of Typed Lua<br>
Gradual Certified Programming in Coq<br>
Relational Algebra by way of Adjunctions<br>
A Co-Contextual Formulation of Type Rules and its Application to Incremental Type Checking<br>
Actario: A Framework for Reasoning About Actor Systems<br>
</div></div>


<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="tools-modeling"><a href="#tools-modeling">Languages for modeling physical systems</a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>A <a href="http://www.giss.nasa.gov/tools/modelE/">climate model</a> is software, but it’s a different kind of software than what most developers normally think about.  Software development usually means developing <i>software systems</i> — code that does useful work “as itself”, such as apps and servers and games.  The purpose of a climate model, on the other hand, is to “be something else” — to simulate a <i>physical system</i> in the world.</p>

<!-- right-column --></div><div class="column-right">

<img src="Images/05-climate-model.png" width="440" height="136">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>A <a href="http://edadocs.software.keysight.com/display/ads2009/About+Model+Development+in+Verilog-A">circuit model</a> or <a href="https://build.openmodelica.org/Documentation/Modelica.Mechanics.html">mechanical model</a>, these days, is essentially software as well.  But again, such a model is not intended to serve as a working software system, but to aid in the design of a working physical system.</p>

<!-- right-column --></div><div class="column-right" style="margin-bottom:-16px;">

<img src="Images/05-circuit-model.png" width="440" height="136">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p style="margin-bottom:18px;">Here are a handful of languages intended for modeling, simulating, or designing physical systems:</p>

<!-- close row --></div></div>

<div class="framed-langs no-preview"><div class="framed-lang">
        <div><a href="https://www.wolfram.com/mathematica/">Mathematica</a> — symbolic manipulation and solving</div>
        <div><a href="https://www.wolfram.com/mathematica/"><img src="Images/05-lang-mathematica.png" width="304" height="140"></a></div>
    </div><div class="framed-lang">
        <div><a href="http://www.mathworks.com/products/simulink/">Simulink</a> — continuous-time dynamic systems</div>
        <div><a href="http://www.mathworks.com/products/simulink/"><img src="Images/05-lang-simulink.png" width="304" height="140"></a></div>
    </div><div class="framed-lang">
        <div><a href="https://www.modelica.org">Modelica</a> — mechanical, electrical, etc systems</div>
        <div><a href="https://www.modelica.org/"><img src="Images/05-lang-modelica.png" width="304" height="140"></a></div>
    </div></div>

<div class="framed-langs no-preview" style="margin-bottom:18px;"><div class="framed-lang">
        <div><a href="https://en.wikipedia.org/wiki/Verilog-AMS">Verilog-AMS</a> — analog and mixed-signal electronics</div>
        <div><a href="https://en.wikipedia.org/wiki/Verilog-AMS"><img src="Images/05-lang-verilog-a.png" width="304" height="140"></a></div>
    </div><div class="framed-lang">
        <div><a href="http://www.esterel-technologies.com">Esterel</a> — reactive control systems</div>
        <div><a href="http://www.esterel-technologies.com"><img src="Images/05-lang-esterel.png" width="304" height="140"></a></div>
    </div><div class="framed-lang">
        <div><a href="http://sbolstandard.org">SBOL</a> — synthetic biology systems</div>
        <div><a href="http://sbolstandard.org"><img src="Images/05-lang-sbol.png" width="304" height="140"></a></div>
    </div></div>
    

<!-- first left-column --><div class="row"><div class="column-left">

<p>Languages like these don’t get mentioned at programming language research <a href="http://splashcon.org">conferences</a>, or in <a href="http://lambda-the-ultimate.org">discussions</a>.  They’re typically dismissed as “<a href="https://en.wikipedia.org/wiki/Domain-specific_language">domain-specific</a>”.  This pejorative reflects a peculiar geocentrism of the programming language community, whose “general-purpose languages” such as Java and Python are in fact very much domain-specific — <i>specific to the domain of software development.</i></p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p><a href="http://book.xogeny.com">Modelica</a> is a programming language, but it is not a language for software development!  It’s for developing physical things that affect the physical world — such as the machinery that participates in energy production, energy storage, and energy consumption.  Data flow in Modelica works like no general-purpose language in existence, because it’s designed around how things influence things in physics, not on a CPU.</p>

<!-- right-column --></div><div style="margin-bottom:10px;" class="column-right">

<img style="margin-top:-12px;" src="Images/05-modelica.png" width="343" height="139">

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>I’ve seen enormous effort expended on languages, tools, and frameworks for software developers.  If you believe that language design can significantly affect the quality of software systems, then it should follow that language design can also affect the quality of energy systems.  And if the quality of such energy systems will, in turn, affect the livability of our planet, then it’s critical that the language development community give modeling languages the attention they deserve.</p>

<!-- right-column --></div><div class="column-right">

<img src="Images/05-devtools.jpg" width="392" height="138">


<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="tools-controlling"><a href="#tools-controlling">Languages for controlling physical systems</a></h3>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>An <a href="https://en.wikipedia.org/wiki/Embedded_system">embedded control system</a> is software, but again, it’s a different kind of software.  Conventional software development is about building systems that live in a <i>virtual</i> world of pixels, files, databases, networks. The embedded controller is part of a physical system, sensing and actuating the <i>physical</i> world.</p>

<p>Every modern piece of equipment producing or consuming energy — every <a href="http://www.winemantech.com/campaign/wind-turbine-embedded-control-systems-for-hil-testing/">wind turbine</a>, <a href="https://en.wikipedia.org/wiki/Battery_management_system">battery system</a>, or <a href="http://www.freescale.com/tools/embedded-software-and-tools/run-time-software/automotive-software-and-tools:ATOSFTWR">vehicle</a> — is built around one or more of these control systems.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure" style="margin-top:-7px;">
<div class="script" data-script="svg 05-control-system" style="width:440px;height:82px;"></div>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>I started my career <a href="http://worrydream.com/jobsearch/jobsearch.html">designing embedded systems</a>.  Standard practice is:  you design and perhaps simulate your system in Matlab or Simulink or pencil.  You implement it in <a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a>.  Sometimes <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a>, sometimes <a href="https://en.wikipedia.org/wiki/Assembly_language">assembly</a>, very occasionally someone will sneak some <a href="https://en.wikipedia.org/wiki/Forth_(programming_language)">Forth</a> or <a href="http://www.lua.org">Lua</a> in there.  But the idea that you might implement a control system in an environment designed for designing control systems — it hasn’t been part of the thinking.  This leads to long feedback loops, inflexible designs, and guesswork engineering.  But most critically, it denies engineers the sort of exploratory environment that fosters novel ideas.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure" style="margin-top:6px;">
<img src="Images/05-embedded-c.png" width="251" height="179">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>There exist methodologies with the right intentions — <a href="https://en.wikipedia.org/wiki/Model-based_design">model-based design</a> with <a href="http://www.mathworks.com/solutions/embedded-code-generation/">generated code</a> seems to be coming into use <a href="http://www.mathworks.com/company/user_stories/bosch-ebike-systems-develops-electric-bike-controller-with-model-based-design.html?by=product">here</a> and <a href="http://www.greencarcongress.com/2009/10/general-motors-developed-twomode-hybrid-powertrain-with-mathworks-modelbased-design-cut-24-months-of.html">there</a> on industrial projects, for example.  But not only are such methods deeply segregated from the mainstream tech community, they are almost antithetical to how today’s programmers are trained to think.</p>

<blockquote>Lessons Learned [from Caterpillar’s pilot project]: Developers who have primarily a control system design background adopt the model-based approach with enthusiasm.  Developers with primarily Computer Science backgrounds are uncomfortable with model-based development and require significantly more time and information prior to adopting the methodology. <span class="cite"><a href="https://www.mathworks.com/tagteam/20303_91198_Caterpillar_2004-01-0894.pdf">(source)</a></span></blockquote>

<!-- right-column --></div><div style="margin-bottom:0px;" class="column-right">

<div class="figure">
<a href="refs/4_Christian_Guss_Improve_Complexity_Management_with__Model-Based_Design_in_V-Modell.pdf"><img src="Images/05-model-based-design.jpg" width="440" height="223"></a>
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>The success of <a href="https://www.arduino.cc">Arduino</a> has had the perhaps retrograde effect of convincing an entire generation that the way to sense and actuate the physical world is through <a href="https://www.arduino.cc/en/Reference/Libraries">imperative method calls in C++</a>, shuffling bits and writing to ports, instead of in an environment designed around signal processing, control theory, and rapid and visible exploration.  As a result, software engineers find a fluid, responsive programming experience on the screen, and a crude and clumsy programming experience in the world.  It’s easier to conjure up virtual fireworks than to blink an LED.  So more and more of our engineers have retreated into the screen.</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<img src="Images/05-arduino.png" width="440" height="174">
</div>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>But <i>climate change happens in the physical world.</i>  The technology to address it must operate on the physical world.  We won’t get that technology without good tools for programming beyond the screen.</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<h3 id="tools-finding"><a href="#tools-finding">Tools for problem-finding</a></h3>

<p>The tools discussed so far are for scientists and engineers working on a problem.  But let’s back up.  How can someone find the right problem to work on in the first place?  And how can they evaluate whether they have the right ideas to solve it?</p>

<h4>Tools for discovering problems</h4>

<p>Everyone knows the high-level areas that need work: ”clean energy”, “carbon capture”, and so on.  But real engineering problems lie in the details — how to <a href="https://news.mit.edu/2015/siting-wind-farms-quickly-cheaply-0717">quickly estimate</a> wind capacity at a location; how to <a href="http://www.caltech.edu/news/caltechs-unique-wind-projects-move-forward-39703">place windmills</a> without aerodynamic interference; how to <a href="http://www.lightsail.com">store energy</a> in compressed air without losing it through heat.</p>

<p>How do we surface these problems?  How can an eager technologist find their way to <i>sub-problems within other people’s projects</i> where they might have a relevant idea?  How can they be exposed to <i>process problems</i> common across many projects?</p>

<!-- left-column --></div></div><div class="row"><div class="column-left">

<p>I know a clean-energy inventor who will browse around a <a href="http://atlas.media.mit.edu/en/visualize/tree_map/hs92/export/all/all/show/2013/">treemap of global exports</a>, as a crude way to get a feel for the “space of industry”.  She’ll see, for example, “gas turbines”, and get interested in ideas for improved gas turbines.  But then what?  Where does she go from there?</p>

<p>She wishes she could simply click on “gas turbines”, and explore the space:</p>

<div class="indent"><p>
What are open problems in the field?<br>
Who’s working on which projects?<br>
What are the fringe ideas?<br>
What are the process bottlenecks?<br>
What dominates cost? What limits adoption?<br>
<i>Why</i> make improvements here?  How would the world benefit?
</p></div>

<p>None of this information is at her fingertips.  Most isn’t even openly available — companies boast about successes, not roadblocks.  For each topic, she would have to spend weeks tracking down and meeting with industry insiders.  What she’d like is a tool that lets her skim across entire fields, browsing problems and discovering where she could be most useful.</p>

<p>There are many reasons, of course, why organizations tend not to publicize their problems.  But in a planetary crisis, the “secretive competitive company” might not be the ideal organizing structure for human effort.  In an admirable gesture of global goodwill, Tesla recently <a href="http://www.teslamotors.com/blog/all-our-patent-are-belong-you">“open-sourced” their patents</a>, but patents represent <i>solutions</i>.  What if there were some way Tesla could reveal their <i>open problems</i>?</p>

<!-- right-column --></div><div class="column-right">

<div class="figure">
<div class="figure-caption" style="margin-bottom:3px;">exports from anywhere to anywhere, Observatory of Economic Complexity <span class="cite"><a href="http://atlas.media.mit.edu/en/visualize/tree_map/hs92/export/all/all/show/2013/">(source)</a></span></div>
<a href="http://atlas.media.mit.edu/en/visualize/tree_map/hs92/export/all/all/show/2013/"><img src="Images/05-treemap.png" width="440" height="481"></a>
</div>


<!-- le
Download .txt
gitextract_g6xedxv7/

├── Fonts/
│   ├── fake_receipt.css
│   ├── hcb.css
│   ├── hcm.css
│   └── sourcesanspro.css
├── Lib/
│   ├── Tangle.js
│   ├── Touchable.js
│   └── sprintf.js
├── Notes/
│   ├── 01-private.txt
│   ├── 02-solar-land.txt
│   ├── 03-all-the-batteries.txt
│   ├── 03-carbon-budget.txt
│   ├── 03-demand-curve.html
│   └── 06-clunker.txt
├── README.md
├── Script/
│   ├── autocomplete-video.js
│   ├── carbon-budget.js
│   ├── chart-data.js
│   ├── charts.js
│   ├── clunker.js
│   ├── main.js
│   └── previews.js
├── Video/
│   ├── 05-dynamic-0.webm
│   ├── 05-dynamic-1.webm
│   ├── 05-dynamic-2.webm
│   ├── 05-dynamic-3.webm
│   ├── 05-dynamic-4.webm
│   ├── 05-dynamic-5.webm
│   └── 06-autocomplete.webm
├── data.html
├── index.html
└── style.css
Download .txt
SYMBOL INDEX (71 symbols across 9 files)

FILE: Lib/Tangle.js
  function initializeElements (line 56) | function initializeElements() {
  function getViewsForElement (line 106) | function getViewsForElement(element, classNames, varNames) {   // initia...
  function getOptionsForElement (line 126) | function getOptionsForElement(element) {   // might use dataset someday
  function constructClass (line 143) | function constructClass(clas, args) {
  function getFormatterForFormat (line 169) | function getFormatterForFormat(formatAttribute, varNames) {
  function getFormatterForCustomFormat (line 179) | function getFormatterForCustomFormat(formatAttribute, varNames) {
  function getFormatterForSprintfFormat (line 209) | function getFormatterForSprintfFormat(formatAttribute, varNames) {
  function addViewSettersForElement (line 233) | function addViewSettersForElement(element, varNames, view) {   // elemen...
  function addFormatSettersForElement (line 249) | function addFormatSettersForElement(element, varNames, formatter) {  // ...
  function addSetterForVariables (line 262) | function addSetterForVariables(setter, varNames) {
  function applySettersForVariables (line 273) | function applySettersForVariables(varNames) {
  function getValue (line 298) | function getValue(varName) {
  function setValue (line 304) | function setValue(varName, value) {
  function setValues (line 310) | function setValues(obj) {
  function getValuesForVariables (line 329) | function getValuesForVariables(varNames) {
  function setModel (line 342) | function setModel(modelClass) {
  function updateModel (line 350) | function updateModel(shouldInitialize) {
  function log (line 375) | function log (msg) {

FILE: Lib/Touchable.js
  function makeTouchable (line 8) | function makeTouchable (el, delegate) {

FILE: Lib/sprintf.js
  function get_type (line 62) | function get_type(variable) {
  function str_repeat (line 65) | function str_repeat(input, multiplier) {

FILE: Script/autocomplete-video.js
  function prepareVideo (line 19) | function prepareVideo (video, div) {
  function updateCanvasWithProgress (line 178) | function updateCanvasWithProgress (canvas, progress) {

FILE: Script/carbon-budget.js
  function getInterceptionPoint (line 41) | function getInterceptionPoint (knobPoint) {
  function clip (line 157) | function clip (x,min,max) { return x < min ? min : x > max ? max : x; }

FILE: Script/charts.js
  function placeChart (line 11) | function placeChart(div, name) {
  function getHTMLForCitation (line 39) | function getHTMLForCitation(what, href) {
  function drawBarChart (line 47) | function drawBarChart (svg,data) {
  function drawStackedBars (line 115) | function drawStackedBars (svg,data) {

FILE: Script/clunker.js
  function commas (line 198) | function commas (v) {
  function appendAllModelDivs (line 227) | function appendAllModelDivs (calculationsRoot) {
  function attachVariableAttributesToSpans (line 235) | function attachVariableAttributesToSpans (root) {
  function getTangleUpdateFunction (line 255) | function getTangleUpdateFunction () {
  function createDistribution (line 276) | function createDistribution (array, comment) {
  function selectWhere (line 280) | function selectWhere (dist, f) {
  function harmonicAverage (line 284) | function harmonicAverage (dist) {
  function getDivForModel (line 296) | function getDivForModel (m) {
  function getHTMLForLine (line 307) | function getHTMLForLine (line) {
  function getHTMLForLineFragment (line 330) | function getHTMLForLineFragment (s, lhs, isResult) {
  function getNameForVariable (line 345) | function getNameForVariable (k) {
  function getHTMLForCommentLine (line 349) | function getHTMLForCommentLine (line) {
  function lockCalculatedResult (line 361) | function lockCalculatedResult (name) {
  function setVariableHovering (line 377) | function setVariableHovering (name, hovering) {
  function initializeHelp (line 392) | function initializeHelp (root) {
  function setHelpShowingForElement (line 397) | function setHelpShowingForElement (el, showing, text) {

FILE: Script/main.js
  function chain (line 25) | function chain (funcs) {
  function setupTableOfContents (line 39) | function setupTableOfContents () {
  function loadScripts (line 58) | function loadScripts () {
  function setupDynamicToolsVideos (line 92) | function setupDynamicToolsVideos () {
  function preloadImages (line 116) | function preloadImages () {
  function nodeArray (line 129) | function nodeArray (nodeList) {
  function createElement (line 133) | function createElement (tag, properties) {
  function hasClass (line 142) | function hasClass (el,clas) {
  function addClass (line 147) | function addClass (el,clas) {
  function removeClass (line 152) | function removeClass (el,clas) {
  function getInheritedAttribute (line 158) | function getInheritedAttribute (el, attr) {
  function ancestorWithClass (line 166) | function ancestorWithClass (el, clas) {
  function ancestorWithTagName (line 177) | function ancestorWithTagName (el, tag) {
  function lerp (line 189) | function lerp (a,b,t) { return a + (b - a) * t; }
  function remap (line 190) | function remap (x,fromLow,fromHigh,toLow,toHigh) { return lerp(toLow, to...

FILE: Script/previews.js
  function setupPreviewSubset (line 26) | function setupPreviewSubset (names, links, from, to, timeout) {
  function loadPreviewImagesWithNames (line 33) | function loadPreviewImagesWithNames (names) {
  function setupPreviewLinks (line 42) | function setupPreviewLinks (links) {
  function setupPreviewLink (line 51) | function setupPreviewLink (link, url) {
  function getPreviewLinks (line 94) | function getPreviewLinks () {
  function getPreviewURLsForLinks (line 103) | function getPreviewURLsForLinks (links) {
  function getPreviewNamesForLinks (line 107) | function getPreviewNamesForLinks (links) {
  function setupRecentScroll (line 117) | function setupRecentScroll () {
  function getPreviewNameForLinkURL (line 132) | function getPreviewNameForLinkURL (url) {
  function getPreviewImageURLForLinkURL (line 136) | function getPreviewImageURLForLinkURL (url) {
  function getPreviewImageURLForName (line 141) | function getPreviewImageURLForName (name) {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (281K chars).
[
  {
    "path": "Fonts/fake_receipt.css",
    "chars": 478,
    "preview": "@font-face {\n    font-family: 'fake_receiptregular';\n    src: url('fake_receipt-webfont.eot');\n    src: url('fake_receip"
  },
  {
    "path": "Fonts/hcb.css",
    "chars": 413,
    "preview": "\n@font-face {\n    font-family: 'hcb';\n    src: url('hcb-webfont.eot');\n    src: url('hcb-webfont.eot?#iefix') format('em"
  },
  {
    "path": "Fonts/hcm.css",
    "chars": 414,
    "preview": "@font-face {\n    font-family: 'hcm';\n    src: url('hcm-webfont.eot');\n    src: url('hcm-webfont.eot?#iefix') format('emb"
  },
  {
    "path": "Fonts/sourcesanspro.css",
    "chars": 2075,
    "preview": "\n@font-face {\n    font-family: 'Source Sans Pro';\n    src: url('sourcesanspro-bold-webfont.eot');\n    src: url('sourcesa"
  },
  {
    "path": "Lib/Tangle.js",
    "chars": 12980,
    "preview": "//\n//  Tangle.js\n//  Tangle 0.1.0\n//\n//  Created by Bret Victor on 5/2/10.\n//  (c) 2011 Bret Victor.  MIT open-source li"
  },
  {
    "path": "Lib/Touchable.js",
    "chars": 2028,
    "preview": "//\n//  Touchable.js\n//\n//  Created by Bret Victor on 3/10/11.\n//  (c) 2011 Bret Victor.  MIT open-source license.\n//\n\nfu"
  },
  {
    "path": "Lib/sprintf.js",
    "chars": 6919,
    "preview": "/**\r\nsprintf() for JavaScript 0.7-beta1\r\nhttp://www.diveintojavascript.com/projects/javascript-sprintf\r\n\r\nCopyright (c) "
  },
  {
    "path": "Notes/01-private.txt",
    "chars": 395,
    "preview": "Cleantech funding numbers are from the PriceWaterhouseCoopers Money Tree reports.\n\n2009-2011: see figure 6 in http://wor"
  },
  {
    "path": "Notes/02-solar-land.txt",
    "chars": 1057,
    "preview": "land in us\n    2,300,000 square miles of land\n        http://www.ers.usda.gov/amber-waves/2012-march/data-feature-how-is"
  },
  {
    "path": "Notes/03-all-the-batteries.txt",
    "chars": 754,
    "preview": "Bill Gates: Innovating to zero, 12:00\nhttps://www.ted.com/talks/bill_gates\n\"All the batteries on Earth can store only 10"
  },
  {
    "path": "Notes/03-carbon-budget.txt",
    "chars": 1205,
    "preview": "carbon emissions 1950-2013:\n    http://www.globalcarbonproject.org/carbonbudget/14/data.htm\n    Global_Carbon_Budget_201"
  },
  {
    "path": "Notes/03-demand-curve.html",
    "chars": 665,
    "preview": "<!DOCTYPE html>\n<html><head>\n    <meta charset=\"UTF-8\">\n    <base target=\"_top\">\n    <style>\n        body {\n            "
  },
  {
    "path": "Notes/06-clunker.txt",
    "chars": 1250,
    "preview": "You can download the raw data, cleaned data, and add-up-the-distribution script at\n\n    http://worrydream.com/ClimateCha"
  },
  {
    "path": "README.md",
    "chars": 103,
    "preview": "What can a technologist do about climate change? A personal view.\nhttp://worrydream.com/ClimateChange/\n"
  },
  {
    "path": "Script/autocomplete-video.js",
    "chars": 6183,
    "preview": "//\n//  autocomplete-video.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  "
  },
  {
    "path": "Script/carbon-budget.js",
    "chars": 4833,
    "preview": "//\n//  carbon-budget.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  MIT o"
  },
  {
    "path": "Script/chart-data.js",
    "chars": 12474,
    "preview": "var chart_data = {};\n\nchart_data[\"01-private-late\"] = {\n    title:\"late-stage venture capital funding in cleantech\",\n   "
  },
  {
    "path": "Script/charts.js",
    "chars": 7444,
    "preview": "//\n//  charts.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  MIT open-sou"
  },
  {
    "path": "Script/clunker.js",
    "chars": 26839,
    "preview": "//\n//  clunker.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  MIT open-so"
  },
  {
    "path": "Script/main.js",
    "chars": 5288,
    "preview": "//\n//  main.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  MIT open-sourc"
  },
  {
    "path": "Script/previews.js",
    "chars": 4588,
    "preview": "//\n//  previews.js\n//  What Can A Technologist Do About Climate Change?\n//\n//  Bret Victor, November 2015\n//  MIT open-s"
  },
  {
    "path": "data.html",
    "chars": 516,
    "preview": "<!DOCTYPE html>\n<html><head>\n    <meta charset=\"UTF-8\">\n    <base target=\"_top\">\n    <script src=\"Script/chart-data.js\" "
  },
  {
    "path": "index.html",
    "chars": 143657,
    "preview": "<!DOCTYPE html>\n<html><head>\n    <meta charset=\"UTF-8\">\n    <base target=\"_top\">\n    <title>What can a technologist do a"
  },
  {
    "path": "style.css",
    "chars": 24168,
    "preview": "* { margin:0; padding:0; }\n\n/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */ \n/* fonts */\n\n@font-face {\n    f"
  }
]

// ... and 7 more files (download for full content)

About this extraction

This page contains the full source code of the worrydream/ClimateChange GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (260.5 KB), approximately 70.9k tokens, and a symbol index with 71 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!