<commit_before>// Import React
import React from "react";
import mapValues from "lodash/mapValues";

// Import Spectacle Core tags
import {
  Appear,
  BlockQuote,
  //Cite,
  CodePane,
  Deck,
  //Fill,
  Heading,
  Image,
  Layout,
  Link,
  List,
  ListItem,
  Markdown,
  Quote,
  Slide,
  Table,
  TableRow,
  TableHeaderItem,
  TableItem
  //Text
} from "spectacle";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./custom.css");

const slideTransition = ["slide"];
const images = mapValues({
  survivejs: require("../images/survivejs.png")
}, (v) => v.replace("/", ""));

preloader(images);

const theme = createTheme({
  primary: "white",
  secondary: "black",
  tertiary: "#09b5c4",
  quartenary: "rgba(255, 219, 169, 0.43)"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Deck transition={slideTransition} transitionDuration={500} theme={theme}>
        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={1} fit caps lineHeight={1} textColor="tertiary">
            Webpack - From Journeyman to Master
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading caps fit size={1}>
            JavaScript Usage on Sites
          </Heading>
          <Markdown>
        {`
* 2011 - 38.2%
* 2013 - 60.4%
* 2015 - 70.5%
* 2016 - 73.5%
* Source: [W3Techs](http://w3techs.com/technologies/history_overview/javascript_library/all/y)
        `}
          </Markdown>
        </Slide>

        <Slide transition={slideTransition}>
          <Appear fid="1">
            <Heading size={2} caps fit>
              Inline JavaScript
            </Heading>
          </Appear>
          <Appear fid="2">
            <Heading size={2} caps fit textColor="tertiary">
              AJAX (async)
            </Heading>
          </Appear>
          <Appear fid="3">
            <Heading size={2} caps fit>
              Single Page Applications
            </Heading>
          </Appear>
          <Appear fid="3">
            <Heading size={2} caps fit textColor="tertiary">
              Universal JavaScript
            </Heading>
          </Appear>
        </Slide>

        <Slide transition={slideTransition} bgColor="black">

            <Quote>Java is to JavaScript as car is to carpet</Quote>

        </Slide>

        <Slide transition={slideTransition}>
          <Heading caps fit size={1}>
            Build Tools
          </Heading>
          <Layout>

                <TableRow>
                  <TableHeaderItem>1st Gen.</TableHeaderItem>
                  <TableHeaderItem>2nd Gen.</TableHeaderItem>
                  <TableHeaderItem>3rd Gen.</TableHeaderItem>
                </TableRow>

                <TableRow>
                  <TableItem>Make</TableItem>
                  <TableItem>Grunt</TableItem>
                  <TableItem>Browserify</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem />
                  <TableItem>Gulp</TableItem>
                  <TableItem>Webpack</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem />
                  <TableItem>Broccoli</TableItem>
                  <TableItem>JSPM</TableItem>
                </TableRow>

          </Layout>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            The Problem of Template
          </Heading>
          <List>
            <Appear><ListItem>Problem 1</ListItem></Appear>
            <Appear><ListItem>Problem 2</ListItem></Appear>
            <Appear><ListItem><Link href="https://facebook.github.io/flux/">Flux</Link> - Actions, stores, dispatcher</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Image src={images.survivejs} margin="40px auto" height="324px" />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={2}>
            Solution
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Minimal Demo
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/demo.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Exercise 1</ListItem></Appear>
            <Appear><ListItem>*Exercise 2</ListItem></Appear>
            <Appear><ListItem>**Exercise 3</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Link href="http://www.survivejs.com/">
            <Heading size={1}>
              SurviveJS
            </Heading>
          </Link>
          <Image src={images.survivejs} margin="0px auto 40px" height="524px"/>
        </Slide>

        <Slide transition={slideTransition} bgColor="tertiary">
          <Heading size={1} caps fit textColor="primary">
            Made in Finland by
          </Heading>
          <Link href="https://twitter.com/bebraw">
            <Heading caps fit size={2} textColor="secondary">
              Juho Vepsäläinen
            </Heading>
          </Link>
        </Slide>
      </Deck>
    );
  }
}
<commit_msg>chore: Add stubs<commit_after>// Import React
import React from "react";
import mapValues from "lodash/mapValues";

// Import Spectacle Core tags
import {
  Appear,
  //BlockQuote,
  //Cite,
  //CodePane,
  Deck,
  //Fill,
  Heading,
  Image,
  //Layout,
  Link,
  List,
  ListItem,
  //Markdown,
  //Quote,
  Slide
  //Table,
  //TableRow,
  //TableHeaderItem,
  //TableItem
  //Text
} from "spectacle";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./custom.css");

const slideTransition = ["slide"];
const images = mapValues({
  survivejs: require("../images/survivejs.png")
}, (v) => v.replace("/", ""));

preloader(images);

const theme = createTheme({
  primary: "white",
  secondary: "black",
  tertiary: "#09b5c4",
  quartenary: "rgba(255, 219, 169, 0.43)"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Deck transition={slideTransition} transitionDuration={500} theme={theme}>
        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={1} fit caps lineHeight={1} textColor="tertiary">
            Webpack - From Journeyman to Master
          </Heading>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Optimizing
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Main Ideas
          </Heading>
          <List>
            <Appear><ListItem>XXX</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Output
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Main Ideas
          </Heading>
          <List>
            <Appear><ListItem>XXX</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Techniques
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Main Ideas
          </Heading>
          <List>
            <Appear><ListItem>XXX</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Packages
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Main Ideas
          </Heading>
          <List>
            <Appear><ListItem>XXX</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Extending
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Main Ideas
          </Heading>
          <List>
            <Appear><ListItem>XXX</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Link href="http://www.survivejs.com/">
            <Heading size={1}>
              SurviveJS
            </Heading>
          </Link>
          <Image src={images.survivejs} margin="0px auto 40px" height="524px"/>
        </Slide>

        <Slide transition={slideTransition} bgColor="tertiary">
          <Heading size={1} caps fit textColor="primary">
            Made in Finland by
          </Heading>
          <Link href="https://twitter.com/bebraw">
            <Heading caps fit size={2} textColor="secondary">
              Juho Vepsäläinen
            </Heading>
          </Link>
        </Slide>
      </Deck>
    );
  }
}
<|endoftext|>


<commit_before>var repCountURL = '/.cbfs/viewproxy/cbfs/_design/cbfs/_view/repcounts?group_level=1';
var refreshInterval = 2000;

var cbfsConfig = {};

function prettySize(s) {
    if (s < 10) {
        return s + "B";
	}
	var e = parseInt(Math.floor(Math.log(s) / Math.log(1024)));
    var sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
	var suffix = sizes[parseInt(e)];
	var val = s / Math.pow(1024, Math.floor(e));
    return val.toFixed(2) + suffix;
}

function updateBubbles(bubble, vis, d) {
    if (!d) {
        return;
    }
    var format = d3.format(",d");

    var children = [];
    for (var n in d) {
        children.push({age: d[n].hbage_ms,
                       hbs: d[n].hbage_str,
                       uptime: d[n].uptime_str,
                       node: n,
                       avail: d[n].free,
                       value: d[n].size,
                       total: d[n].free + d[n].size});
    }

    function fill(val) {
        var offset = Math.min(1, val / 180000);
        return d3.interpolateRgb("#bbf", "#f55")(offset);
    }

    var data = bubble.nodes({children: children})
        .filter(function(d) { return !d.children; });

    var dKey = function(d) { return d.node; };

    var node = vis.selectAll("g.node")
        .data(data, dKey)
      .enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    vis.selectAll("g.node")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    vis.selectAll("g.node")
        .data(data, dKey)
      .exit().transition()
        .duration(1000)
        .attr("transform", function(d) {
            return "translate(" + d.x + "," + vis.attr("height") + ")";
        })
        .ease('quad')
        .remove();

    node.append("title")
        .text(function(d) { return d.node + ": " + format(d.value); });

    node.append("path")
        .attr("class", "arc arcf")
        .style("fill", "white")
        .each(function(d) { this._current = {value: 0, r: d.r}; });

    node.append("path")
        .attr("class", "arc arce")
        .style("fill", "#ddd")
        .each(function(d) { this._current = {value: 0, r: d.r}; });

    node.append("text")
        .attr("text-anchor", "middle")
        .attr("dy", ".3em")
        .text(function(d) { return d.node.substring(0, d.r / 3); });

    vis.selectAll("g.node text")
        .data(data, dKey)
        .text(function(d) {
            return d.node + " " + prettySize(d.value) + "/" + prettySize(d.avail);
        });

    function arcTween(a) {
        var i = d3.interpolate(this._current, {r: a.r, value: (a.value / a.total) * (2 * Math.PI)});
        this._current = i(0);
        var isArce = d3.select(this).attr('class').indexOf('arce') >= 0;
        return function(t) {
            var x = i(t);
            var start = 0, end = x.value;
            if (isArce) {
                start = end;
                end = 2 * Math.PI;
            }
            return d3.svg.arc().innerRadius(0).outerRadius(x.r).startAngle(start).endAngle(end)();
        };
    }

    vis.selectAll("g.node .arcf")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .style("fill", function(d) { return fill(d.age); })
        .attrTween("d", arcTween);

    vis.selectAll("g.node .arce")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .style("fill", function(d) { return d3.interpolate(fill(d.age), 'white')(0.8); })
        .attrTween("d", arcTween);

    vis.selectAll("g.node title")
        .data(data, dKey)
        .text(function(d) {
            var rv = "Last heartbeat from " + d.node + " " + d.hbs + " ago";
            if (d.uptime) {
                rv += ", up " + d.uptime;
            }
            return rv;
        });

}

function drawBubbles(d, r) {
    if (!r) {
        r = Math.min(window.innerWidth - 25, window.innerHeight);
    }
    var bubble = d3.layout.pack()
        .sort(null)
        .size([r, r])
        .padding(1.5);

    var vis = d3.select("#bubbles").append("svg")
        .attr("width", r)
        .attr("height", r)
        .attr("class", "bubble");

    updateBubbles(bubble, vis, d);
    return function(x) {
        updateBubbles(bubble, vis, x);
    };
}

function addNodeSizes(d) {
    var rv = {totalUsed: 0, totalFree: 0};

    for (var k in d) {
        rv.totalUsed += d[k].used;
        rv.totalFree += d[k].free;
    }

    return rv;
}

function drawSizeChart(d) {
    console.log(addNodeSizes(d));

    var h = window.innerHeight - 4, w = 20;

    var svg = d3.select("#size").append("svg")
        .attr("width", w)
        .attr("height", h);

    var r = svg.selectAll("rect")
        .data(["avail", "used"])
      .enter().append("rect")
        .attr("class", String)
        .attr("width", w)
        .attr("x", 2)
        .attr("y", 0);
    svg.selectAll("text")
        .data(["avail", "used"])
        .enter().append("text")
        .attr("class", String)
        .attr("transform", "rotate(90)")
        .attr("x", 10)
        .attr("y", -5);

    function rv(x) {
        console.log("Updating size chart", addNodeSizes(d));
        var sizes = addNodeSizes(x);
        var total = sizes.totalFree + sizes.totalUsed;
        var y = d3.scale.linear().domain([0, total]).rangeRound([h, 2]);

        d3.select("#size rect.used")
            .attr("title", prettySize(sizes.totalUsed))
          .transition().duration(1000)
            .attr("height", y(0))
            .attr("y", y(sizes.totalUsed));
        d3.select("#size rect.avail")
            .attr("title", prettySize(sizes.totalFree))
          .transition().duration(1000)
            .attr("height", y(sizes.totalUsed))
            .attr("y", y(total));

        d3.select("#size text.used")
            .text("Used: " + prettySize(sizes.totalUsed))
          .transition().duration(1000)
            .attr("x", function(d) { return y(sizes.totalUsed) + 10;});
        d3.select("#size text.avail")
            .text("Available: " + prettySize(sizes.totalFree));
    };
    rv(d);
    return rv;
}

function drawRepcounts(d) {
    var vals = [],
        names = [],
        formatNumber = d3.format(",d");

    for (var i = 0; i < d.rows.length; i++) {
        names.push(d.rows[i].key);
        vals.push(parseInt(d.rows[i].value));
    }

    var w = 200, bh = 20;

    var x = d3.scale.linear()
        .domain([0, d3.max(vals)])
        .range([0, w]);

    var textify = function(d, i) {
        return names[i] + " rep: " + formatNumber(d);
    };

    var repChart = d3.select("#repcounts svg");

    var dKey = function(d, i) { return names[i]; };

    repChart.selectAll("rect")
        .data(vals, dKey)
      .enter().append("rect")
        .attr("y", function(d, i) { return i * bh; })
        .attr("width", x)
        .attr("x", 0)
        .attr("height", bh);

    repChart.selectAll("rect")
        .data(vals, dKey)
      .exit().remove();

    repChart.selectAll("rect")
        .data(vals, dKey)
        .attr("class", function(d, i) {
            return parseInt(names[i]) < (cbfsConfig.minrepl || 2) ? "under" : null;
        })
      .transition()
        .attr("width", x)
        .attr("x", 0);

    repChart.selectAll("text")
        .data(vals, dKey)
      .enter().append("text");

    repChart.selectAll("text")
        .data(vals, dKey)
      .exit().remove();

    repChart.selectAll("text")
        .data(vals, dKey)
        .attr("x", 10)
        .attr("y", function(d, i) { return bh * (1 + i);})
        .attr("dx", -3)
        .attr("dy", "-5")
        .attr("text-anchor", "start")
        .attr("class", function(d, i) {
            return (parseInt(names[i]) < (cbfsConfig.minrepl || 2) && x(d,i) < 10) ? "under" : null;
        })
        .text(textify);
}

function updateCBFSConfig() {
    d3.json("/.cbfs/config/", function(d) {
        if (d) {
            cbfsConfig = d;
        }
    });
}

function reltime(time){
    var date = new Date(time.replace(/-/g,"/").replace("T", " ").replace("Z", " +0000").replace(/(\d*\:\d*:\d*)\.\d*/g,"$1")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff)) return time;

    return day_diff < 1 && (
        diff < 60 && "just now" ||
            diff < 120 && "1 minute ago" ||
            diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
            diff < 7200 && "1 hour ago" ||
            diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
        day_diff == 1 && "yesterday" ||
        day_diff < 21 && day_diff + " days ago" ||
        day_diff < 45 && Math.ceil( day_diff / 7 ) + " weeks ago" ||
        time;
}

function updateTasks() {
    var tlist = d3.select("#tasklist");
    d3.json("/.cbfs/tasks/", function(json) {

        d3.select("#taskhdr")
            .style("display", d3.entries(json).length > 0 ? 'block' : 'none');

        tlist.selectAll("li.toplevel")
            .data(d3.keys(json), String)
            .exit().remove();

        var iul = tlist.selectAll("li")
            .data(d3.keys(json), String)
          .enter().append("li")
            .attr("class", "toplevel")
            .text(String)
            .append("ul");

        iul.selectAll("li.toplevel")
            .data(function(d) { return d3.entries(json[d]); })
          .enter().append("li");

        tlist.selectAll("li.toplevel")
            .data(d3.keys(json), String)
          .selectAll("ul li")
            .data(function(d) { return d3.entries(json[d]); })
            .attr("title", function(d) {
                if (d.value.state == "preparing") {
                    return "preparing";
                }
                return reltime(d.value.ts);
            })
            .attr("class", function(d) { return d.value.state; })
            .text(function(d) { return d.key; });
    });
}

function monitorInit() {
    console.log("Starting monitoring");

    var repChart = d3.select("#repcounts").append("svg")
        .attr("class", "chart")
        .attr("width", 200);

    updateCBFSConfig();
    setInterval(function() {
        updateCBFSConfig();
    }, 60000);

    setInterval(function() {
        updateTasks();
    }, 5000);

    d3.json("/.cbfs/nodes/", function(d) {
        var updates = [];
        updates.push(drawBubbles(d));
        updates.push(drawSizeChart(d));

        setInterval(function() {
            d3.json("/.cbfs/nodes/", function(d) {
                for (var i = 0; i < updates.length; i++) {
                    updates[i](d);
                }
            });
        }, refreshInterval);
    });

    setInterval(function() {
        d3.json(repCountURL, drawRepcounts);
    }, refreshInterval);
}

function showFileTreeMap(w, h, json1) {
    function cell() {
        this.style("left", function(d) { return d.x + "px"; })
            .style("top", function(d) { return d.y + "px"; })
            .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
            .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; })
            .attr("title", function(d) {
                return d.name + ": " + prettySize(d.size) +
                    " / " + d.descendants + " descendants";
            })
            .on('click', function(x) {
                history.pushState({path:x.path}, x.path, window.location + x.path);
                updateFileMap(w, h, x.path);
            });
    }

    function pathJoin(a, b) {
        while (a.charAt(a.length-1) == "/") {
            a = a.slice(0, -1);
        }
        while (b.charAt(0) == "/") {
            b = b.slice(1);
        }
        return a + "/" + b;
    }

    var color = d3.scale.category20c();

    var d3data = {name: json1.path, "children": []};

    for (k in json1.dirs) {
        d3data.children.push({
            name: k,
            children: json1.dirs[k],
            size: json1.dirs[k].size,
            descendants: json1.dirs[k].descendants,
            path: pathJoin(json1.path, k)
        });
    }

    var treemap = d3.layout.treemap()
        .size([w, h])
        .sticky(true)
        .value(function(d) { return d.size; });

    d3.select("#files").data([d3data]).selectAll("div")
        .data(treemap.nodes)
            .attr("class", "cell")
        .style("background", function(d) { return color(d.name);})
        .text(function(d) { return d.name; })
        .call(cell)
      .exit().remove();

    d3.select("#files").data([d3data]).selectAll("div")
        .data(treemap.nodes)
      .enter().append("div")
        .attr("class", "cell")
        .style("background", function(d) { return color(d.name);})
        .text(function(d) { return d.name; })
        .call(cell);
}

function updateFileMap(w, h, path) {
    d3.json("/.cbfs/list" + path, function(j1) {
        showFileTreeMap(w, h, j1);
    });
}

function fileInit(w, h, path) {
    updateFileMap(w, h, path);
}<commit_msg>Don't let the used get too close to the available.<commit_after>var repCountURL = '/.cbfs/viewproxy/cbfs/_design/cbfs/_view/repcounts?group_level=1';
var refreshInterval = 2000;

var cbfsConfig = {};

function prettySize(s) {
    if (s < 10) {
        return s + "B";
	}
	var e = parseInt(Math.floor(Math.log(s) / Math.log(1024)));
    var sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
	var suffix = sizes[parseInt(e)];
	var val = s / Math.pow(1024, Math.floor(e));
    return val.toFixed(2) + suffix;
}

function updateBubbles(bubble, vis, d) {
    if (!d) {
        return;
    }
    var format = d3.format(",d");

    var children = [];
    for (var n in d) {
        children.push({age: d[n].hbage_ms,
                       hbs: d[n].hbage_str,
                       uptime: d[n].uptime_str,
                       node: n,
                       avail: d[n].free,
                       value: d[n].size,
                       total: d[n].free + d[n].size});
    }

    function fill(val) {
        var offset = Math.min(1, val / 180000);
        return d3.interpolateRgb("#bbf", "#f55")(offset);
    }

    var data = bubble.nodes({children: children})
        .filter(function(d) { return !d.children; });

    var dKey = function(d) { return d.node; };

    var node = vis.selectAll("g.node")
        .data(data, dKey)
      .enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    vis.selectAll("g.node")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    vis.selectAll("g.node")
        .data(data, dKey)
      .exit().transition()
        .duration(1000)
        .attr("transform", function(d) {
            return "translate(" + d.x + "," + vis.attr("height") + ")";
        })
        .ease('quad')
        .remove();

    node.append("title")
        .text(function(d) { return d.node + ": " + format(d.value); });

    node.append("path")
        .attr("class", "arc arcf")
        .style("fill", "white")
        .each(function(d) { this._current = {value: 0, r: d.r}; });

    node.append("path")
        .attr("class", "arc arce")
        .style("fill", "#ddd")
        .each(function(d) { this._current = {value: 0, r: d.r}; });

    node.append("text")
        .attr("text-anchor", "middle")
        .attr("dy", ".3em")
        .text(function(d) { return d.node.substring(0, d.r / 3); });

    vis.selectAll("g.node text")
        .data(data, dKey)
        .text(function(d) {
            return d.node + " " + prettySize(d.value) + "/" + prettySize(d.avail);
        });

    function arcTween(a) {
        var i = d3.interpolate(this._current, {r: a.r, value: (a.value / a.total) * (2 * Math.PI)});
        this._current = i(0);
        var isArce = d3.select(this).attr('class').indexOf('arce') >= 0;
        return function(t) {
            var x = i(t);
            var start = 0, end = x.value;
            if (isArce) {
                start = end;
                end = 2 * Math.PI;
            }
            return d3.svg.arc().innerRadius(0).outerRadius(x.r).startAngle(start).endAngle(end)();
        };
    }

    vis.selectAll("g.node .arcf")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .style("fill", function(d) { return fill(d.age); })
        .attrTween("d", arcTween);

    vis.selectAll("g.node .arce")
        .data(data, dKey)
      .transition()
        .duration(1000)
        .style("fill", function(d) { return d3.interpolate(fill(d.age), 'white')(0.8); })
        .attrTween("d", arcTween);

    vis.selectAll("g.node title")
        .data(data, dKey)
        .text(function(d) {
            var rv = "Last heartbeat from " + d.node + " " + d.hbs + " ago";
            if (d.uptime) {
                rv += ", up " + d.uptime;
            }
            return rv;
        });

}

function drawBubbles(d, r) {
    if (!r) {
        r = Math.min(window.innerWidth - 25, window.innerHeight);
    }
    var bubble = d3.layout.pack()
        .sort(null)
        .size([r, r])
        .padding(1.5);

    var vis = d3.select("#bubbles").append("svg")
        .attr("width", r)
        .attr("height", r)
        .attr("class", "bubble");

    updateBubbles(bubble, vis, d);
    return function(x) {
        updateBubbles(bubble, vis, x);
    };
}

function addNodeSizes(d) {
    var rv = {totalUsed: 0, totalFree: 0};

    for (var k in d) {
        rv.totalUsed += d[k].used;
        rv.totalFree += d[k].free;
    }

    return rv;
}

function drawSizeChart(d) {
    console.log(addNodeSizes(d));

    var h = window.innerHeight - 4, w = 20;

    var svg = d3.select("#size").append("svg")
        .attr("width", w)
        .attr("height", h);

    var r = svg.selectAll("rect")
        .data(["avail", "used"])
      .enter().append("rect")
        .attr("class", String)
        .attr("width", w)
        .attr("x", 2)
        .attr("y", 0);
    svg.selectAll("text")
        .data(["avail", "used"])
        .enter().append("text")
        .attr("class", String)
        .attr("transform", "rotate(90)")
        .attr("x", 10)
        .attr("y", -5);

    function rv(x) {
        console.log("Updating size chart", addNodeSizes(d));
        var sizes = addNodeSizes(x);
        var total = sizes.totalFree + sizes.totalUsed;
        var y = d3.scale.linear().domain([0, total]).rangeRound([h, 2]);

        d3.select("#size rect.used")
            .attr("title", prettySize(sizes.totalUsed))
          .transition().duration(1000)
            .attr("height", y(0))
            .attr("y", y(sizes.totalUsed));
        d3.select("#size rect.avail")
            .attr("title", prettySize(sizes.totalFree))
          .transition().duration(1000)
            .attr("height", y(sizes.totalUsed))
            .attr("y", y(total));

        d3.select("#size text.used")
            .text("Used: " + prettySize(sizes.totalUsed))
          .transition().duration(1000)
            .attr("x", function(d) { return Math.max(y(sizes.totalUsed) + 10, 200);});
        d3.select("#size text.avail")
            .text("Available: " + prettySize(sizes.totalFree));
    };
    rv(d);
    return rv;
}

function drawRepcounts(d) {
    var vals = [],
        names = [],
        formatNumber = d3.format(",d");

    for (var i = 0; i < d.rows.length; i++) {
        names.push(d.rows[i].key);
        vals.push(parseInt(d.rows[i].value));
    }

    var w = 200, bh = 20;

    var x = d3.scale.linear()
        .domain([0, d3.max(vals)])
        .range([0, w]);

    var textify = function(d, i) {
        return names[i] + " rep: " + formatNumber(d);
    };

    var repChart = d3.select("#repcounts svg");

    var dKey = function(d, i) { return names[i]; };

    repChart.selectAll("rect")
        .data(vals, dKey)
      .enter().append("rect")
        .attr("y", function(d, i) { return i * bh; })
        .attr("width", x)
        .attr("x", 0)
        .attr("height", bh);

    repChart.selectAll("rect")
        .data(vals, dKey)
      .exit().remove();

    repChart.selectAll("rect")
        .data(vals, dKey)
        .attr("class", function(d, i) {
            return parseInt(names[i]) < (cbfsConfig.minrepl || 2) ? "under" : null;
        })
      .transition()
        .attr("width", x)
        .attr("x", 0);

    repChart.selectAll("text")
        .data(vals, dKey)
      .enter().append("text");

    repChart.selectAll("text")
        .data(vals, dKey)
      .exit().remove();

    repChart.selectAll("text")
        .data(vals, dKey)
        .attr("x", 10)
        .attr("y", function(d, i) { return bh * (1 + i);})
        .attr("dx", -3)
        .attr("dy", "-5")
        .attr("text-anchor", "start")
        .attr("class", function(d, i) {
            return (parseInt(names[i]) < (cbfsConfig.minrepl || 2) && x(d,i) < 10) ? "under" : null;
        })
        .text(textify);
}

function updateCBFSConfig() {
    d3.json("/.cbfs/config/", function(d) {
        if (d) {
            cbfsConfig = d;
        }
    });
}

function reltime(time){
    var date = new Date(time.replace(/-/g,"/").replace("T", " ").replace("Z", " +0000").replace(/(\d*\:\d*:\d*)\.\d*/g,"$1")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff)) return time;

    return day_diff < 1 && (
        diff < 60 && "just now" ||
            diff < 120 && "1 minute ago" ||
            diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
            diff < 7200 && "1 hour ago" ||
            diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
        day_diff == 1 && "yesterday" ||
        day_diff < 21 && day_diff + " days ago" ||
        day_diff < 45 && Math.ceil( day_diff / 7 ) + " weeks ago" ||
        time;
}

function updateTasks() {
    var tlist = d3.select("#tasklist");
    d3.json("/.cbfs/tasks/", function(json) {

        d3.select("#taskhdr")
            .style("display", d3.entries(json).length > 0 ? 'block' : 'none');

        tlist.selectAll("li.toplevel")
            .data(d3.keys(json), String)
            .exit().remove();

        var iul = tlist.selectAll("li")
            .data(d3.keys(json), String)
          .enter().append("li")
            .attr("class", "toplevel")
            .text(String)
            .append("ul");

        iul.selectAll("li.toplevel")
            .data(function(d) { return d3.entries(json[d]); })
          .enter().append("li");

        tlist.selectAll("li.toplevel")
            .data(d3.keys(json), String)
          .selectAll("ul li")
            .data(function(d) { return d3.entries(json[d]); })
            .attr("title", function(d) {
                if (d.value.state == "preparing") {
                    return "preparing";
                }
                return reltime(d.value.ts);
            })
            .attr("class", function(d) { return d.value.state; })
            .text(function(d) { return d.key; });
    });
}

function monitorInit() {
    console.log("Starting monitoring");

    var repChart = d3.select("#repcounts").append("svg")
        .attr("class", "chart")
        .attr("width", 200);

    updateCBFSConfig();
    setInterval(function() {
        updateCBFSConfig();
    }, 60000);

    setInterval(function() {
        updateTasks();
    }, 5000);

    d3.json("/.cbfs/nodes/", function(d) {
        var updates = [];
        updates.push(drawBubbles(d));
        updates.push(drawSizeChart(d));

        setInterval(function() {
            d3.json("/.cbfs/nodes/", function(d) {
                for (var i = 0; i < updates.length; i++) {
                    updates[i](d);
                }
            });
        }, refreshInterval);
    });

    setInterval(function() {
        d3.json(repCountURL, drawRepcounts);
    }, refreshInterval);
}

function showFileTreeMap(w, h, json1) {
    function cell() {
        this.style("left", function(d) { return d.x + "px"; })
            .style("top", function(d) { return d.y + "px"; })
            .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
            .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; })
            .attr("title", function(d) {
                return d.name + ": " + prettySize(d.size) +
                    " / " + d.descendants + " descendants";
            })
            .on('click', function(x) {
                history.pushState({path:x.path}, x.path, window.location + x.path);
                updateFileMap(w, h, x.path);
            });
    }

    function pathJoin(a, b) {
        while (a.charAt(a.length-1) == "/") {
            a = a.slice(0, -1);
        }
        while (b.charAt(0) == "/") {
            b = b.slice(1);
        }
        return a + "/" + b;
    }

    var color = d3.scale.category20c();

    var d3data = {name: json1.path, "children": []};

    for (k in json1.dirs) {
        d3data.children.push({
            name: k,
            children: json1.dirs[k],
            size: json1.dirs[k].size,
            descendants: json1.dirs[k].descendants,
            path: pathJoin(json1.path, k)
        });
    }

    var treemap = d3.layout.treemap()
        .size([w, h])
        .sticky(true)
        .value(function(d) { return d.size; });

    d3.select("#files").data([d3data]).selectAll("div")
        .data(treemap.nodes)
            .attr("class", "cell")
        .style("background", function(d) { return color(d.name);})
        .text(function(d) { return d.name; })
        .call(cell)
      .exit().remove();

    d3.select("#files").data([d3data]).selectAll("div")
        .data(treemap.nodes)
      .enter().append("div")
        .attr("class", "cell")
        .style("background", function(d) { return color(d.name);})
        .text(function(d) { return d.name; })
        .call(cell);
}

function updateFileMap(w, h, path) {
    d3.json("/.cbfs/list" + path, function(j1) {
        showFileTreeMap(w, h, j1);
    });
}

function fileInit(w, h, path) {
    updateFileMap(w, h, path);
}<|endoftext|>


<commit_before>import React from "react";

// Import Spectacle Core tags
import {
	Appear,
	BlockQuote,
	Cite,
	Code,
	CodePane,
	Deck,
	Heading,
	Image,
	Fill,
	Fit,
	Layout,
	ListItem,
	List,
	Quote,
	Slide,
	Text
} from "spectacle";
import CodeSlide from 'spectacle-code-slide';
import LinkList from "./LinkList";
import BasicExample from "./BasicExample";
import AppearingText from "./AppearingText";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

function lines(start, end, text) {
	return text.split("\n").slice(start, end).join("\n");
}

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./index.css");
require("./prism-solarizedlight.css");

const images = {
	associatedDomain: require("../assets/associatedDomains.png").replace("/", "")
};

preloader(images);

const theme = createTheme({
	primary: "#FDF6E3",
	secondary: "#586E75",
	tertiary: "#268BD2",
	quartenary: "#657b83"
}, {
	primary: "Montserrat",
	secondary: "Helvetica"
});
const bgColor = "#FDF6E3";
const color = "#268BD2";

export default class Presentation extends React.Component {
	render() {
		return (
			<Deck transition={[]} transitionDuration={500} theme={theme}>
				<Slide transition={["zoom"]} bgColor="primary">
					<Heading size={1} fit caps lineHeight={1} textColor="secondary">
						Routes and Links
					</Heading>
					<Text margin="10px 0 0" textColor="tertiary" size={1} fit bold>
						Using React Router v4 with React Native
					</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>What is React Router?</Heading>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>React interface to History API in browsers</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Maps URLs to Components</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>What's new?</Heading>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Multiple Routers / Packages</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}><Route> Simplified</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}><Switch/></Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Native support!</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Multiple Routers / Packages</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(0, 6, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(6, 11, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(12, 16, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps><Route> Simplified</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./RouteExample.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} caps>Basic Example</Heading>
					<BasicExample/>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps><Switch></Heading>
					<Heading size={7}>Renders the first child that matches</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={lines(1, 6, require("!!raw-loader!./Switch.example").trim())}
								style={{ fontSize: 24 }}
							/>
						</Fit>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./Switch.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Native Support</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./NativeSupport.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Implementing Deep Links</Heading>
					<Heading size={7} textColor="secondary">iOS</Heading>
					<AppearingText textColor="quaternary" padding={20}>Setup SSL on your site ✓</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Add apple-app-site-association file</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Add Associated Domain Entitlement</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Update AppDelegate</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Listen to Linking events</AppearingText>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary">ADD apple-app-site-association FILE</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={require("!!raw-loader!./apple-app-site-association.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
					<AppearingText textColor="secondary" textSize={24}>* do not add a .json file extension </AppearingText>
					<AppearingText fontSize={32} padding={12}>🤦</AppearingText >
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Add Associated Domain Entitlement</Heading>
					<Heading size={7} textColor="secondary">Xcode > Target > Capabilities</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fill>
							<Image src={images.associatedDomain} width={708} style={{
								borderColor: '#ccc',
								borderWidth: 1,
								borderStyle: 'solid'
							}}/>
						</Fill>
					</Layout>
					<Layout style={{ justifyContent: 'center' }}>
						applinks:yourdomain.com
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Update AppDelegate</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="objectivec"
								source={[
									lines(13, 17, require("!!raw-loader!../Demo/ios/Demo/AppDelegate.m")),
									lines(37, 46, require("!!raw-loader!../Demo/ios/Demo/AppDelegate.m"))
								].join("\n")}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Listen to Linking events</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={require("!!raw-loader!./Linking.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Implementing Deep Links</Heading>
					<Heading size={7} textColor="secondary">Android</Heading>
					<AppearingText textColor="quaternary" padding={20}>Update AndroidManifest.xml</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Listen to Linking events</AppearingText>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Update AndroidManifest.xml</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./AndroidManifest.example.xml").trim()}
								style={{ fontSize: 24, maxWidth: 'none' }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["zoom", "fade"]} bgColor="secondary">

						<Heading size={4} textColor="primary">Demos</Heading>

					<Layout>
						<Fill>
							<video src={require("../assets/demo-ios.mov").replace("/", "")} autoPlay loop style={{ height: 640 }}/>
						</Fill>
						<Fill>
							<video src={require("../assets/demo-android.mov").replace("/", "")} autoPlay loop style={{ height: 640 }}/>
						</Fill>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Resources</Heading>
					<LinkList links={[{
						href: "https://reacttraining.com/react-router/",
						title: "React Router"
					}, {
						href: "https://facebook.github.io/react-native/docs/linking.html",
						title: "Linking - React Native"
					}, {
						href: "https://developer.apple.com/videos/play/wwdc2015/509/",
						title: "Seamless Linking in Your App (WWDC '15)"
					}, {
						href: "https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html",
						title: "Support Universal Links"
					}, {
						href: "http://building.usebutton.com/debugging/ios/deep-linking/links/universal-links/2016/03/31/debugging-universal-links/",
						title: "Debugging Universal Links"
					}, {
						href: "https://github.com/ReactTraining/react-router/tree/v4/packages/react-router-native/experimental",
						title: "<StackRoutes> and <TabRoutes>"
					}, {
						href: "https://reactnavigation.org/",
						title: "React Navigation"
					}]}
					/>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading caps>Questions?</Heading>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading caps>Thanks!</Heading>
					<Text textColor="secondary" style={{ paddingTop: 20 }}>github / bspaulding</Text>
					<Text textColor="secondary" style={{ paddingTop: 20 }}>twitter / bradspaulding</Text>
				</Slide>
			</Deck>
		);
	}
}
<commit_msg>small tweaks<commit_after>import React from "react";

// Import Spectacle Core tags
import {
	Appear,
	BlockQuote,
	Cite,
	Code,
	CodePane,
	Deck,
	Heading,
	Image,
	Fill,
	Fit,
	Layout,
	Link,
	ListItem,
	List,
	Quote,
	Slide,
	Text
} from "spectacle";
import CodeSlide from 'spectacle-code-slide';
import LinkList from "./LinkList";
import BasicExample from "./BasicExample";
import AppearingText from "./AppearingText";

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

function lines(start, end, text) {
	return text.split("\n").slice(start, end).join("\n");
}

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./index.css");
require("./prism-solarizedlight.css");

const images = {
	associatedDomain: require("../assets/associatedDomains.png").replace("/", "")
};

preloader(images);

const theme = createTheme({
	primary: "#FDF6E3",
	secondary: "#586E75",
	tertiary: "#268BD2",
	quartenary: "#657b83"
}, {
	primary: "Montserrat",
	secondary: "Helvetica"
});
const bgColor = "#FDF6E3";
const color = "#268BD2";

export default class Presentation extends React.Component {
	render() {
		return (
			<Deck transition={[]} transitionDuration={500} theme={theme}>
				<Slide transition={["zoom"]} bgColor="primary">
					<Heading size={1} fit caps lineHeight={1} textColor="secondary">
						Routes and Deep Linking
					</Heading>
					<Text margin="10px 0 0" textColor="tertiary" size={1} fit bold>
						React Router v4 and React Native
					</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>What is React Router?</Heading>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>React interface to History API in browsers</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Maps URLs to Components</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>What's new?</Heading>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Multiple Routers / Packages</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}><Route> Simplified</Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}><Switch/></Text>
					<Text textColor="quaternary" style={{ paddingTop: 20 }}>Native support!</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Multiple Routers / Packages</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(0, 6, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(6, 11, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={lines(12, 16, require("!!raw-loader!./Routers.example"))}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps><Route> Simplified</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./RouteExample.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} caps>Basic Example</Heading>
					<BasicExample/>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps><Switch></Heading>
					<Heading size={7}>Renders the first child that matches</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={lines(1, 6, require("!!raw-loader!./Switch.example").trim())}
								style={{ fontSize: 24 }}
							/>
						</Fit>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./Switch.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Native Support</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./NativeSupport.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>What is Deep Linking?</Heading>
					<Text textColor="secondary">
						Handle your website's URLs
					</Text>
					<Text textColor="secondary">
						inside your native app
					</Text>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Implementing Deep Links</Heading>
					<Heading size={7} textColor="secondary">iOS</Heading>
					<AppearingText textColor="quaternary" padding={20}>Setup SSL on your site ✓</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Add apple-app-site-association file</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Add Associated Domain Entitlement</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Update AppDelegate</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Listen to Linking events</AppearingText>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary">ADD apple-app-site-association FILE</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={require("!!raw-loader!./apple-app-site-association.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
					<AppearingText textColor="secondary" textSize={24}>* do not add a .json file extension </AppearingText>
					<AppearingText fontSize={32} padding={12}>🤦</AppearingText >
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Add Associated Domain Entitlement</Heading>
					<Heading size={7} textColor="secondary">Xcode > Target > Capabilities</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fill>
							<Image src={images.associatedDomain} width={708} style={{
								borderColor: '#ccc',
								borderWidth: 1,
								borderStyle: 'solid'
							}}/>
						</Fill>
					</Layout>
					<Layout style={{ justifyContent: 'center' }}>
						applinks:yourdomain.com
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Update AppDelegate</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="objectivec"
								source={[
									lines(13, 17, require("!!raw-loader!../Demo/ios/Demo/AppDelegate.m")),
									lines(37, 46, require("!!raw-loader!../Demo/ios/Demo/AppDelegate.m"))
								].join("\n")}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Listen to Linking events</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="javascript"
								source={require("!!raw-loader!./Linking.example").trim()}
								style={{ fontSize: 24 }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Implementing Deep Links</Heading>
					<Heading size={7} textColor="secondary">Android</Heading>
					<AppearingText textColor="quaternary" padding={20}>Update AndroidManifest.xml</AppearingText>
					<AppearingText textColor="quaternary" padding={20}>Listen to Linking events</AppearingText>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Update AndroidManifest.xml</Heading>
					<Layout style={{ justifyContent: 'center' }}>
						<Fit>
							<CodePane
								lang="jsx"
								source={require("!!raw-loader!./AndroidManifest.example.xml").trim()}
								style={{ fontSize: 24, maxWidth: 'none' }}
							/>
						</Fit>
					</Layout>
				</Slide>
				<Slide transition={["zoom", "fade"]} bgColor="secondary">

						<Heading size={4} textColor="primary">Demos</Heading>

					<Layout>
						<Fill>
							<video src={require("../assets/demo-ios.mov").replace("/", "")} autoPlay loop style={{ height: 720, position: 'relative', top: -20 }}/>
						</Fill>
						<Fill>
							<video src={require("../assets/demo-android.mov").replace("/", "")} autoPlay loop style={{ height: 720, position: 'relative', top: -20 }}/>
						</Fill>
					</Layout>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading size={6} textColor="secondary" caps>Resources</Heading>
					<LinkList links={[{
						href: "https://reacttraining.com/react-router/",
						title: "React Router"
					}, {
						href: "https://facebook.github.io/react-native/docs/linking.html",
						title: "Linking - React Native"
					}, {
						href: "https://developer.apple.com/videos/play/wwdc2015/509/",
						title: "Seamless Linking in Your App (WWDC '15)"
					}, {
						href: "https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html",
						title: "Support Universal Links"
					}, {
						href: "http://building.usebutton.com/debugging/ios/deep-linking/links/universal-links/2016/03/31/debugging-universal-links/",
						title: "Debugging Universal Links"
					}, {
						href: "https://github.com/ReactTraining/react-router/tree/v4/packages/react-router-native/experimental",
						title: "<StackRoutes> and <TabRoutes>"
					}, {
						href: "https://reactnavigation.org/",
						title: "React Navigation"
					}]}
					/>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading caps>Questions?</Heading>
				</Slide>
				<Slide transition={["slide"]}>
					<Heading caps>Thanks!</Heading>
					<Text textColor="secondary" style={{ paddingTop: 20 }}>github / bspaulding</Text>
					<Text textColor="secondary" style={{ paddingTop: 20 }}>twitter / bradspaulding</Text>
					<Text textColor="tertiary" style={{ fontSize: 21, paddingTop: 40 }}>
						<Link to="https://github.com/bspaulding/presentation-react-router-4-universal-links">
							Slides at github.com/bspaulding/presentation-react-router-4-universal-links
						</Link>
					</Text>
				</Slide>
			</Deck>
		);
	}
}
<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var ViewFactory = require('../../view_factory');
var randomQuote = require('../../view_helpers/random_quote');
var LikeView = require('../likes/view');
var MapCardPreview = require('../mapcard_preview');
var Visualizations = require('./feed_collection');

module.exports = cdb.core.View.extend({
  tagName: 'div',

  _PAGE: 1,
  _ITEMS_PER_PAGE: 4,

  _SMALL_WIDTH: 520,

  _CARD_HEIGHT: 170,
  _LOADER_TITLE: 'Loading visualizations',

  events: {
    'click .js-more': '_onClickMore'
  },

  initialize: function() {
    _.bindAll(this, '_initLike', '_onWindowResize', '_renderStaticMaps');

    this._initTemplates();
    this._initModels();
    this._initBindings();
  },

  render: function() {
    this.$el.html(this.template());
    this._renderLoader();
    this._fetchItems({ page: this._PAGE });

    return this;
  },

  _onWindowResize: function() {
    var width = $(window).width();

    if (width <= this._SMALL_WIDTH) {
      this.model.set('size', 'small');
    } else {
      this.model.set('size', 'big');
    }

    this._renderStaticMaps();
  },

  _initTemplates: function() {
    this.template = cdb.templates.getTemplate('common/views/feed/template');
    this.mapTemplate = cdb.templates.getTemplate('common/views/feed/map_item_template');
    this.datasetTemplate = cdb.templates.getTemplate('common/views/feed/dataset_item_template');
    this.loaderTemplatePath = 'common/views/feed/loading';
    this.emptyTemplatePath = 'common/views/feed/empty';
    this.errorTemplatePath = 'common/views/feed/error';
  },

  _initModels: function() {
    var size = 'big';
    var wWidth = $(window).width();

    if (wWidth <= this._SMALL_WIDTH) {
      size = 'small';
    }

    this.model = new cdb.Backbone.Model({
      vis_count: 0,
      type: '',
      size: size,
      page: 0,
      order_by: 'likes'
    });

    this.collection = new Visualizations();
    this.collection.bind('reset', this._renderVisualizations, this);
    this._likeModels = new Backbone.Collection();
  },

  _initBindings: function() {
    var self = this;

    this.model.bind('change:show_more', this._onChangeShowMore, this);
    this.model.bind('change:show_loader', this._onChangeShowLoader, this);
    this.model.bind('change:show_mast', this._onChangeShowMast, this);
    this.model.bind('change:vis_count', this._onChangeVisCount, this);

    this.options.authenticatedUser.bind('change', function() {
      self._onAuthenticatedUserChange();
      self._initLikes();
    }, this);

    $(window).bind('resize', this._onWindowResize);
  },

  _onChangeVisCount: function() {
    if (this.model.get('vis_count') >= this.collection.total_entries) {
      this.model.set({ show_more: false });
    } else {
      this.model.set({ show_more: true });
    }
  },

  _onChangeShowMast: function() {
    if (this.model.get('show_mast')) {
      this.$('.js-mast').removeClass('is-hidden');
    } else {
      this.$('.js-mast').addClass('is-hidden');
    }
  },

  _onChangeShowLoader: function() {
    if (this.model.get('show_loader')) {
      this.loader.show();
    } else {
      this.loader.hide();
    }
  },

  _onChangeShowMore: function() {
    if (this.model.get('show_more')) {
      this.$('.js-more').removeClass('is-transparent');
    } else {
      this.$('.js-more').addClass('is-transparent');
    }
  },

  _renderLoader: function() {
    this.loader = ViewFactory.createByTemplate(this.loaderTemplatePath, {
      title: this._LOADER_TITLE,
      quote: randomQuote()
    });

    this.$el.append(this.loader.render().$el);
  },

  /*_renderError: function() {
    this.loader = ViewFactory.createByTemplate(this.errorTemplatePath, {
      title: this._LOADER_TITLE,
      quote: randomQuote()
    });

    this.$el.append(this.loader.render().$el);
  },*/

  _renderEmpty: function() {
    this.empty = ViewFactory.createByTemplate(this.emptyTemplatePath, {
      name: config.user_name
    });

    this.$el.append(this.empty.render().$el);
  },

  _getGeometryType: function(geomTypes) {
    if (geomTypes && geomTypes.length > 0) {
      var types = ['point', 'polygon', 'line', 'raster'];
      var geomType = geomTypes[0];

      return _.find(types, function(type) {
        return geomType.toLowerCase().indexOf(type) !== -1;
      });

    } else {
      return null;
    }
  },

  _renderVisualizations: function() {

    if (this.collection.length === 0) {
      this.model.set({ show_loader: false });
      this._renderEmpty();
      return;
    }

    this.model.set({ vis_count: this.model.get('vis_count') + this.collection.length, show_loader: false, show_more: true, show_filters: true, show_mast: true });

    this.collection.each(function(item) {
      var template = item.get('type') === 'derived' ? this.mapTemplate : this.datasetTemplate;

      var el = template({
        vis: item.attributes,
        username: item.get('permission').owner.username,
        avatar_url: item.get('permission').owner.avatar_url,
        table_count: item.get('permission').owner.table_count,
        maps_count: item.get('permission').owner.maps_count,
        geomType: item.get('table') && item.get('table').geometry_types ? this._getGeometryType(item.get('table').geometry_types) : null,
        account_host: 'cartodb.com' //, config.account_host
      });

      this.$('.js-items').append(el);

      var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
      if (item.get('type') === 'derived' && !item.get('rendered_' + this.model.get('size'))) {
        this._renderStaticMap(item, $item);
      }

    }, this);

    this._initLikes();
  },

  _renderStaticMaps: function() {
    this.collection.each(function(item) {
      if (item.get('type') === 'derived' && !item.get('rendered_' + this.model.get('size'))) {
        var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
        this._renderStaticMap(item, $item);
      }
    }, this);
  },

  _renderStaticMap: function(vis, $el) {

    var visId = vis.get('id');
    var username = vis.get('permission').owner.username;

    var width = 540;

    if (this.model.get('size') === 'small') {
      width = 288;
    }

    var className = 'is-' + this.model.get('size');

    if (visId && username) {

      vis.set('rendered_' + this.model.get('size'), true);

      new MapCardPreview({
        el: $el.find('.js-header'),
        width: width,
        height: this._CARD_HEIGHT,
        account_host: config.maps_api_template.replace(/https?:\/\/{user}\./, ""),
        username: username,
        visId: visId,
        className: className
      }).load();
    }
  },

  _initLikes: function() {
    this.collection.each(function(item) {
      var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
      this._initLike(item, $item.find('.js-like'));
    }, this);
  },

  _getLikesEndpoint: function(vis) {
    return '/api/v1/viz/' + vis.get('id') + '/like';
  },

  _initLike: function(vis, $el) {
    var likeable = this.options.authenticatedUser && this.options.authenticatedUser.get('username');

    if (likeable) {
      var url = this._getLikesEndpoint(vis);

      var likeModel = cdb.admin.Like.newByVisData({
        url: url,
        likeable: likeable,
        show_count: true,
        show_label: true,
        vis_id: vis.get('id'),
        likes: vis.get('likes')
      });

      if (likeable) {
        likeModel.fetch();
      }

      this._likeModels.push(likeModel);

      var likeView = new LikeView({
        el: $el,
        model: likeModel
      });

      likeView.render();
    }
  },

  _onAuthenticatedUserChange: function() {
    if (this.options.authenticatedUser.get('username')) {
      this._likeModels.each(function(model) {
        model.set('likeable', true);
        model.fetch();
      });
    }
  },

  _fetchItems: function(params) {
    var data = _.extend({ types: 'table,derived', per_page: this._ITEMS_PER_PAGE, order: 'updated_at', error: this._onFetchError }, params);
    this.collection.fetch({
      data: data
    });
  },

  _onFetchError: function() {
    // TODO: add error
  },

  _onClickMore: function(e) {
    this.killEvent(e);
    this.model.set({ show_more: false, show_loader: true });
    this._fetchItems({ page: ++this._PAGE });
  }
});
<commit_msg>Fixes small width to load the previews<commit_after>var cdb = require('cartodb.js');
var ViewFactory = require('../../view_factory');
var randomQuote = require('../../view_helpers/random_quote');
var LikeView = require('../likes/view');
var MapCardPreview = require('../mapcard_preview');
var Visualizations = require('./feed_collection');

module.exports = cdb.core.View.extend({
  tagName: 'div',

  _PAGE: 1,
  _ITEMS_PER_PAGE: 4,

  _SMALL_WIDTH: 544,

  _CARD_HEIGHT: 170,
  _LOADER_TITLE: 'Loading visualizations',

  events: {
    'click .js-more': '_onClickMore'
  },

  initialize: function() {
    _.bindAll(this, '_initLike', '_onWindowResize', '_renderStaticMaps');

    this._initTemplates();
    this._initModels();
    this._initBindings();
  },

  render: function() {
    this.$el.html(this.template());
    this._renderLoader();
    this._fetchItems({ page: this._PAGE });

    return this;
  },

  _onWindowResize: function() {
    var width = $(window).width();

    if (width <= this._SMALL_WIDTH) {
      this.model.set('size', 'small');
    } else {
      this.model.set('size', 'big');
    }

    this._renderStaticMaps();
  },

  _initTemplates: function() {
    this.template = cdb.templates.getTemplate('common/views/feed/template');
    this.mapTemplate = cdb.templates.getTemplate('common/views/feed/map_item_template');
    this.datasetTemplate = cdb.templates.getTemplate('common/views/feed/dataset_item_template');
    this.loaderTemplatePath = 'common/views/feed/loading';
    this.emptyTemplatePath = 'common/views/feed/empty';
    this.errorTemplatePath = 'common/views/feed/error';
  },

  _initModels: function() {
    var size = 'big';
    var wWidth = $(window).width();

    if (wWidth <= this._SMALL_WIDTH) {
      size = 'small';
    }

    this.model = new cdb.Backbone.Model({
      vis_count: 0,
      type: '',
      size: size,
      page: 0,
      order_by: 'likes'
    });

    this.collection = new Visualizations();
    this.collection.bind('reset', this._renderVisualizations, this);
    this._likeModels = new Backbone.Collection();
  },

  _initBindings: function() {
    var self = this;

    this.model.bind('change:show_more', this._onChangeShowMore, this);
    this.model.bind('change:show_loader', this._onChangeShowLoader, this);
    this.model.bind('change:show_mast', this._onChangeShowMast, this);
    this.model.bind('change:vis_count', this._onChangeVisCount, this);

    this.options.authenticatedUser.bind('change', function() {
      self._onAuthenticatedUserChange();
      self._initLikes();
    }, this);

    $(window).bind('resize', this._onWindowResize);
  },

  _onChangeVisCount: function() {
    if (this.model.get('vis_count') >= this.collection.total_entries) {
      this.model.set({ show_more: false });
    } else {
      this.model.set({ show_more: true });
    }
  },

  _onChangeShowMast: function() {
    if (this.model.get('show_mast')) {
      this.$('.js-mast').removeClass('is-hidden');
    } else {
      this.$('.js-mast').addClass('is-hidden');
    }
  },

  _onChangeShowLoader: function() {
    if (this.model.get('show_loader')) {
      this.loader.show();
    } else {
      this.loader.hide();
    }
  },

  _onChangeShowMore: function() {
    if (this.model.get('show_more')) {
      this.$('.js-more').removeClass('is-transparent');
    } else {
      this.$('.js-more').addClass('is-transparent');
    }
  },

  _renderLoader: function() {
    this.loader = ViewFactory.createByTemplate(this.loaderTemplatePath, {
      title: this._LOADER_TITLE,
      quote: randomQuote()
    });

    this.$el.append(this.loader.render().$el);
  },

  /*_renderError: function() {
    this.loader = ViewFactory.createByTemplate(this.errorTemplatePath, {
      title: this._LOADER_TITLE,
      quote: randomQuote()
    });

    this.$el.append(this.loader.render().$el);
  },*/

  _renderEmpty: function() {
    this.empty = ViewFactory.createByTemplate(this.emptyTemplatePath, {
      name: config.user_name
    });

    this.$el.append(this.empty.render().$el);
  },

  _getGeometryType: function(geomTypes) {
    if (geomTypes && geomTypes.length > 0) {
      var types = ['point', 'polygon', 'line', 'raster'];
      var geomType = geomTypes[0];

      return _.find(types, function(type) {
        return geomType.toLowerCase().indexOf(type) !== -1;
      });

    } else {
      return null;
    }
  },

  _renderVisualizations: function() {

    if (this.collection.length === 0) {
      this.model.set({ show_loader: false });
      this._renderEmpty();
      return;
    }

    this.model.set({ vis_count: this.model.get('vis_count') + this.collection.length, show_loader: false, show_more: true, show_filters: true, show_mast: true });

    this.collection.each(function(item) {
      var template = item.get('type') === 'derived' ? this.mapTemplate : this.datasetTemplate;

      var el = template({
        vis: item.attributes,
        username: item.get('permission').owner.username,
        avatar_url: item.get('permission').owner.avatar_url,
        table_count: item.get('permission').owner.table_count,
        maps_count: item.get('permission').owner.maps_count,
        geomType: item.get('table') && item.get('table').geometry_types ? this._getGeometryType(item.get('table').geometry_types) : null,
        account_host: 'cartodb.com' //, config.account_host
      });

      this.$('.js-items').append(el);

      var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
      if (item.get('type') === 'derived' && !item.get('rendered_' + this.model.get('size'))) {
        this._renderStaticMap(item, $item);
      }

    }, this);

    this._initLikes();
  },

  _renderStaticMaps: function() {
    this.collection.each(function(item) {
      if (item.get('type') === 'derived' && !item.get('rendered_' + this.model.get('size'))) {
        var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
        this._renderStaticMap(item, $item);
      }
    }, this);
  },

  _renderStaticMap: function(vis, $el) {

    var visId = vis.get('id');
    var username = vis.get('permission').owner.username;

    var width = 540;

    if (this.model.get('size') === 'small') {
      width = 288;
    }

    var className = 'is-' + this.model.get('size');

    if (visId && username) {

      vis.set('rendered_' + this.model.get('size'), true);

      new MapCardPreview({
        el: $el.find('.js-header'),
        width: width,
        height: this._CARD_HEIGHT,
        account_host: config.maps_api_template.replace(/https?:\/\/{user}\./, ""),
        username: username,
        visId: visId,
        className: className
      }).load();
    }
  },

  _initLikes: function() {
    this.collection.each(function(item) {
      var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
      this._initLike(item, $item.find('.js-like'));
    }, this);
  },

  _getLikesEndpoint: function(vis) {
    return '/api/v1/viz/' + vis.get('id') + '/like';
  },

  _initLike: function(vis, $el) {
    var likeable = this.options.authenticatedUser && this.options.authenticatedUser.get('username');

    if (likeable) {
      var url = this._getLikesEndpoint(vis);

      var likeModel = cdb.admin.Like.newByVisData({
        url: url,
        likeable: likeable,
        show_count: true,
        show_label: true,
        vis_id: vis.get('id'),
        likes: vis.get('likes')
      });

      if (likeable) {
        likeModel.fetch();
      }

      this._likeModels.push(likeModel);

      var likeView = new LikeView({
        el: $el,
        model: likeModel
      });

      likeView.render();
    }
  },

  _onAuthenticatedUserChange: function() {
    if (this.options.authenticatedUser.get('username')) {
      this._likeModels.each(function(model) {
        model.set('likeable', true);
        model.fetch();
      });
    }
  },

  _fetchItems: function(params) {
    var data = _.extend({ types: 'table,derived', per_page: this._ITEMS_PER_PAGE, order: 'updated_at', error: this._onFetchError }, params);
    this.collection.fetch({
      data: data
    });
  },

  _onFetchError: function() {
    // TODO: add error
  },

  _onClickMore: function(e) {
    this.killEvent(e);
    this.model.set({ show_more: false, show_loader: true });
    this._fetchItems({ page: ++this._PAGE });
  }
});
<|endoftext|>


<commit_before>import { mat4 } from 'gl-matrix';

import {
  AmbientLight,
  Color,
  Constants,
  DirectionalLight,
  Geometry,
  Lights,
  LineGeometry,
  MathUtils,
  Mesh,
  OrbitControls,
  PerspectiveCamera,
  ArrayUtils,
  RayCaster,
  Renderer,
  Scene,
  Shader,
  ShaderChunks,
  SphereGeometry,
  Texture,
  Vector2,
  Vector3
} from '../../../../src/index.ts';
import DRACOLoader from '../draco/DRACOLoader';
import Decal from './decal';

const { guiController } = require('../gui')(['webgl2']);

// Shader parser needs to be fixed for webgl1

// Renderer
const renderer = new Renderer({
  ratio: window.innerWidth / window.innerHeight,
  prefferedContext: guiController.context
});
renderer.setDevicePixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.canvas);

// Scene
const scene = new Scene();

// Camera
const camera = new PerspectiveCamera({
  fov: 45,
  ratio: window.innerWidth / window.innerHeight
});

camera.position.set(25, 10, 25);
camera.lookAt();

// Helpers
const controls = new OrbitControls(camera, renderer.canvas);
controls.smoothing = true;

controls.update();

const ambientLight = new Lights([
  new AmbientLight({
    intensity: {
      type: 'f',
      value: 0.7
    }
  })
]);

const directionalLights = new Lights([
  new DirectionalLight({
    intensity: {
      type: 'f',
      value: 1.7
    },
    color: {
      type: '3f',
      value: new Color(0xffffff).v
    }
  })
]);

directionalLights.get()[0].position.set(0.13, 0.34, -0.14);

scene.ambientLight = ambientLight;
scene.directionalLights = directionalLights;

const normalMap = new Texture({
  src: 'assets/models/draco/goethe-lifemask/normal-map.jpg'
});

const dracoLoader = new DRACOLoader(undefined, 'assets/third-party/draco');
let face;
dracoLoader.load(
  'assets/models/draco/goethe-lifemask/goeth-lifemask.drc',
  geometry => {
    face = new Mesh(
      geometry,
      new Shader({
        directionalLights,
        ambientLight,
        type: 'lambert',
        hookVertexPre: `
        uniform float uFogDensity;
        out float vFogAmount;
        ${ShaderChunks.Fog.exp2}
      `,
        hookVertexEnd: `
        float fogDistance = length(gl_Position.xyz);
        vFogAmount = fogExp2(fogDistance, uFogDensity);
      `,
        hookFragmentPre: `
        in float vFogAmount;
        uniform sampler2D uNormalMap;
      `,
        hookFragmentMain: `
        normal = texture(uNormalMap, vUv).xyz;
      `,
        hookFragmentEnd: `
        vec3 fogColor = vec3(0.0);
        outgoingColor = vec4(mix(color, fogColor, vFogAmount), 1.0);
      `,
        uniforms: {
          uDiffuse: {
            type: '3f',
            value: new Color(0xffffff).v
          },
          uNormalMap: {
            type: 't',
            value: normalMap.texture
          },
          uFogDensity: {
            type: 'f',
            value: 0.054
          }
        }
      })
    );

    scene.add(face);
  }
);

// Line helper
const points = [...[0, 0, 0], ...[1, 1, 1]];
const bufferVertices = new Float32Array(points);

const line = new Mesh(
  new LineGeometry(bufferVertices),
  new Shader({
    drawType: Constants.DRAW_LINES
  })
);
scene.add(line);

const intersectHelper = new Mesh(new SphereGeometry(0.2), new Shader());
scene.add(intersectHelper);

const raycaster = new RayCaster();
const mouse = new Vector2();

const paintMaps = [
  new Texture({ src: 'assets/textures/paint/splatter-0.jpg' }),
  new Texture({ src: 'assets/textures/paint/splatter-1.jpg' }),
  new Texture({ src: 'assets/textures/paint/splatter-2.jpg' })
];

let intersect = null;
function onMouseClick() {
  if (intersect === null) return;
  const eye = new Vector3(1, 1, 1)
    .multiply(intersect.face.normal.clone())
    .add(intersect.point.clone()).v;

  const target = intersect.point.clone().v;

  const rotationQuat = MathUtils.lookAt(eye, target, Vector3.up.v);
  const matrixFromQuat = mat4.fromQuat(mat4.create(), rotationQuat);

  // https://github.com/mrdoob/three.js/blob/master/src/math/Euler.js#L133
  const m11 = matrixFromQuat[0];
  const m12 = matrixFromQuat[4];
  const m13 = matrixFromQuat[8];
  const m22 = matrixFromQuat[5];
  const m23 = matrixFromQuat[9];
  const m32 = matrixFromQuat[6];
  const m33 = matrixFromQuat[10];

  let x;
  let z;
  const y = Math.asin(MathUtils.clamp(m13, -1, 1));
  if (Math.abs(m13) < 0.99999) {
    x = Math.atan2(-m23, m33);
    z = Math.atan2(-m12, m11);
  } else {
    x = Math.atan2(m32, m22);
    z = 0;
  }

  const position = intersect.point.clone();
  const rotation = new Vector3(x, y, z);
  const scale = MathUtils.lerp(4, 10, Math.random());
  const dimensions = new Vector3(scale, scale, scale);
  const check = new Vector3(1, 1, 1);

  rotation.z = Math.random() * 2 * Math.PI;

  const decal = new Decal(face, position, rotation, dimensions, check);
  const data = decal.compute();
  decal.dispose();

  // Offset decal mesh from face
  data.vertices.forEach(vertex => {
    vertex.scale(1.001);
  });

  const verts = ArrayUtils.flatten(data.vertices);
  const normals = ArrayUtils.flatten(data.normals);
  const uvs = ArrayUtils.flatten(data.uvs);

  const geometry = new Geometry(
    new Float32Array(verts),
    new Uint16Array(data.indices),
    new Float32Array(normals),
    new Float32Array(uvs)
  );

  const decalMesh = new Mesh(
    geometry,
    new Shader({
      type: 'lambert',
      ambientLight,
      directionalLights,
      hookFragmentPre: `
        uniform sampler2D uPaint;
        ${ShaderChunks.Packing.packNormalToRGB}
    `,
      hookFragmentMain: `
        color = packNormalToRGB(normal);
        vec4 texel = texture(uPaint, vUv);
    `,
      hookFragmentEnd: `
        if (texel.r > 0.9) {
          discard;
        }
        outgoingColor.a = 1.0 - texel.r;
      `,
      uniforms: {
        uPaint: {
          type: 't',
          value: paintMaps[Math.floor(Math.random() * paintMaps.length)].texture
        },
        uNormalMap: {
          type: 't',
          value: normalMap.texture
        }
      },
      blending: false
    })
  );

  scene.add(decalMesh);
}

function onMouseMove(event) {
  mouse.x = event.clientX / window.innerWidth * 2 - 1;
  mouse.y = -(event.pageY / window.innerHeight * 2 - 1);
}

function resize() {
  const width = window.innerWidth;
  const height = window.innerHeight;
  renderer.setSize(width, height);
  camera.ratio = width / height;
  camera.updateProjectionMatrix();
}
resize();

window.addEventListener('resize', resize);
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('click', onMouseClick);

function update() {
  requestAnimationFrame(update);

  controls.update();

  if (face) {
    raycaster.setFromCamera(mouse, scene, camera, face);
    intersect = raycaster.intersectObject(face);

    if (intersect) {
      intersectHelper.position.copy(intersect.point);
      intersectHelper.visible = true;
      line.visible = true;
      const v0 = intersect.point.clone();
      const v1 = new Vector3(2, 2, 2).multiply(intersect.face.normal.clone());
      v1.add(intersect.point.clone());
      line.geometry.vertices[0].copy(v0);
      line.geometry.vertices[1].copy(v1);
      line.geometry.updateVertices();
    } else {
      intersectHelper.visible = false;
      line.visible = false;
    }
  }

  camera.updateMatrixWorld();
  renderer.render(scene, camera);
}
update();
<commit_msg>No need for alpha blending<commit_after>import { mat4 } from 'gl-matrix';

import {
  AmbientLight,
  Color,
  Constants,
  DirectionalLight,
  Geometry,
  Lights,
  LineGeometry,
  MathUtils,
  Mesh,
  OrbitControls,
  PerspectiveCamera,
  ArrayUtils,
  RayCaster,
  Renderer,
  Scene,
  Shader,
  ShaderChunks,
  SphereGeometry,
  Texture,
  Vector2,
  Vector3
} from '../../../../src/index.ts';
import DRACOLoader from '../draco/DRACOLoader';
import Decal from './decal';

const { guiController } = require('../gui')(['webgl2']);

// Shader parser needs to be fixed for webgl1

// Renderer
const renderer = new Renderer({
  ratio: window.innerWidth / window.innerHeight,
  prefferedContext: guiController.context
});
renderer.setDevicePixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.canvas);

// Scene
const scene = new Scene();

// Camera
const camera = new PerspectiveCamera({
  fov: 45,
  ratio: window.innerWidth / window.innerHeight
});

camera.position.set(25, 10, 25);
camera.lookAt();

// Helpers
const controls = new OrbitControls(camera, renderer.canvas);
controls.smoothing = true;

controls.update();

const ambientLight = new Lights([
  new AmbientLight({
    intensity: {
      type: 'f',
      value: 0.7
    }
  })
]);

const directionalLights = new Lights([
  new DirectionalLight({
    intensity: {
      type: 'f',
      value: 1.7
    },
    color: {
      type: '3f',
      value: new Color(0xffffff).v
    }
  })
]);

directionalLights.get()[0].position.set(0.13, 0.34, -0.14);

scene.ambientLight = ambientLight;
scene.directionalLights = directionalLights;

const normalMap = new Texture({
  src: 'assets/models/draco/goethe-lifemask/normal-map.jpg'
});

const dracoLoader = new DRACOLoader(undefined, 'assets/third-party/draco');
let face;
dracoLoader.load(
  'assets/models/draco/goethe-lifemask/goeth-lifemask.drc',
  geometry => {
    face = new Mesh(
      geometry,
      new Shader({
        directionalLights,
        ambientLight,
        type: 'lambert',
        hookVertexPre: `
        uniform float uFogDensity;
        out float vFogAmount;
        ${ShaderChunks.Fog.exp2}
      `,
        hookVertexEnd: `
        float fogDistance = length(gl_Position.xyz);
        vFogAmount = fogExp2(fogDistance, uFogDensity);
      `,
        hookFragmentPre: `
        in float vFogAmount;
        uniform sampler2D uNormalMap;
      `,
        hookFragmentMain: `
        normal = texture(uNormalMap, vUv).xyz;
      `,
        hookFragmentEnd: `
        vec3 fogColor = vec3(0.0);
        outgoingColor = vec4(mix(color, fogColor, vFogAmount), 1.0);
      `,
        uniforms: {
          uDiffuse: {
            type: '3f',
            value: new Color(0xffffff).v
          },
          uNormalMap: {
            type: 't',
            value: normalMap.texture
          },
          uFogDensity: {
            type: 'f',
            value: 0.054
          }
        }
      })
    );

    scene.add(face);
  }
);

// Line helper
const points = [...[0, 0, 0], ...[1, 1, 1]];
const bufferVertices = new Float32Array(points);

const line = new Mesh(
  new LineGeometry(bufferVertices),
  new Shader({
    drawType: Constants.DRAW_LINES
  })
);
scene.add(line);

const intersectHelper = new Mesh(new SphereGeometry(0.2), new Shader());
scene.add(intersectHelper);

const raycaster = new RayCaster();
const mouse = new Vector2();

const paintMaps = [
  new Texture({ src: 'assets/textures/paint/splatter-0.jpg' }),
  new Texture({ src: 'assets/textures/paint/splatter-1.jpg' }),
  new Texture({ src: 'assets/textures/paint/splatter-2.jpg' })
];

let intersect = null;
function onMouseClick() {
  if (intersect === null) return;
  const eye = new Vector3(1, 1, 1)
    .multiply(intersect.face.normal.clone())
    .add(intersect.point.clone()).v;

  const target = intersect.point.clone().v;

  const rotationQuat = MathUtils.lookAt(eye, target, Vector3.up.v);
  const matrixFromQuat = mat4.fromQuat(mat4.create(), rotationQuat);

  // https://github.com/mrdoob/three.js/blob/master/src/math/Euler.js#L133
  const m11 = matrixFromQuat[0];
  const m12 = matrixFromQuat[4];
  const m13 = matrixFromQuat[8];
  const m22 = matrixFromQuat[5];
  const m23 = matrixFromQuat[9];
  const m32 = matrixFromQuat[6];
  const m33 = matrixFromQuat[10];

  let x;
  let z;
  const y = Math.asin(MathUtils.clamp(m13, -1, 1));
  if (Math.abs(m13) < 0.99999) {
    x = Math.atan2(-m23, m33);
    z = Math.atan2(-m12, m11);
  } else {
    x = Math.atan2(m32, m22);
    z = 0;
  }

  const position = intersect.point.clone();
  const rotation = new Vector3(x, y, z);
  const scale = MathUtils.lerp(4, 10, Math.random());
  const dimensions = new Vector3(scale, scale, scale);
  const check = new Vector3(1, 1, 1);

  rotation.z = Math.random() * 2 * Math.PI;

  const decal = new Decal(face, position, rotation, dimensions, check);
  const data = decal.compute();
  decal.dispose();

  // Offset decal mesh from face
  data.vertices.forEach(vertex => {
    vertex.scale(1.001);
  });

  const verts = ArrayUtils.flatten(data.vertices);
  const normals = ArrayUtils.flatten(data.normals);
  const uvs = ArrayUtils.flatten(data.uvs);

  const geometry = new Geometry(
    new Float32Array(verts),
    new Uint16Array(data.indices),
    new Float32Array(normals),
    new Float32Array(uvs)
  );

  const decalMesh = new Mesh(
    geometry,
    new Shader({
      type: 'lambert',
      ambientLight,
      directionalLights,
      hookFragmentPre: `
        uniform sampler2D uPaint;
        ${ShaderChunks.Packing.packNormalToRGB}
    `,
      hookFragmentMain: `
        color = packNormalToRGB(normal);
        vec4 texel = texture(uPaint, vUv);
    `,
      hookFragmentEnd: `
        if (texel.r > 0.9) {
          discard;
        }
      `,
      uniforms: {
        uPaint: {
          type: 't',
          value: paintMaps[Math.floor(Math.random() * paintMaps.length)].texture
        },
        uNormalMap: {
          type: 't',
          value: normalMap.texture
        }
      }
    })
  );

  scene.add(decalMesh);
}

function onMouseMove(event) {
  mouse.x = event.clientX / window.innerWidth * 2 - 1;
  mouse.y = -(event.pageY / window.innerHeight * 2 - 1);
}

function resize() {
  const width = window.innerWidth;
  const height = window.innerHeight;
  renderer.setSize(width, height);
  camera.ratio = width / height;
  camera.updateProjectionMatrix();
}
resize();

window.addEventListener('resize', resize);
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('click', onMouseClick);

function update() {
  requestAnimationFrame(update);

  controls.update();

  if (face) {
    raycaster.setFromCamera(mouse, scene, camera, face);
    intersect = raycaster.intersectObject(face);

    if (intersect) {
      intersectHelper.position.copy(intersect.point);
      intersectHelper.visible = true;
      line.visible = true;
      const v0 = intersect.point.clone();
      const v1 = new Vector3(2, 2, 2).multiply(intersect.face.normal.clone());
      v1.add(intersect.point.clone());
      line.geometry.vertices[0].copy(v0);
      line.geometry.vertices[1].copy(v1);
      line.geometry.updateVertices();
    } else {
      intersectHelper.visible = false;
      line.visible = false;
    }
  }

  camera.updateMatrixWorld();
  renderer.render(scene, camera);
}
update();
<|endoftext|>


<commit_before>'use strict';
const {useState, useContext} = require('react');
const React = require('react');
const {render, useInput, Box, Text, AppContext} = require('../..');

const Robot = () => {
	const {exit} = useContext(AppContext);
	const [x, setX] = useState(1);
	const [y, setY] = useState(1);

	useInput((input, key) => {
		if (input === 'q') {
			exit();
		}

		if (key.leftArrow) {
			setX(Math.max(1, x - 1));
		}

		if (key.rightArrow) {
			setX(Math.min(20, x + 1));
		}

		if (key.upArrow) {
			setY(Math.max(1, y - 1));
		}

		if (key.downArrow) {
			setY(Math.min(10, y + 1));
		}
	});

	return (
		<Box flexDirection="column">
			<Text>Use arrow keys to move the face. Press “q” to exit.</Text>
			<Box height={12} paddingLeft={x} paddingTop={y}>
				<Text>^_^</Text>
			</Box>
		</Box>
	);
};

render(<Robot />);
<commit_msg>Update useInput example<commit_after>'use strict';
const React = require('react');
const {render, useInput, useApp, Box, Text} = require('../..');

const Robot = () => {
	const {exit} = useApp();
	const [x, setX] = React.useState(1);
	const [y, setY] = React.useState(1);

	useInput((input, key) => {
		if (input === 'q') {
			exit();
		}

		if (key.leftArrow) {
			setX(Math.max(1, x - 1));
		}

		if (key.rightArrow) {
			setX(Math.min(20, x + 1));
		}

		if (key.upArrow) {
			setY(Math.max(1, y - 1));
		}

		if (key.downArrow) {
			setY(Math.min(10, y + 1));
		}
	});

	return (
		<Box flexDirection="column">
			<Text>Use arrow keys to move the face. Press “q” to exit.</Text>
			<Box height={12} paddingLeft={x} paddingTop={y}>
				<Text>^_^</Text>
			</Box>
		</Box>
	);
};

render(<Robot />);
<|endoftext|>


<commit_before>#!/usr/bin/env node

const { catchGlobalErrors } = require('@xen-orchestra/log/configure.js')
const { createLogger } = require('@xen-orchestra/log')
const { getSyncedHandler } = require('@xen-orchestra/fs')
const { join } = require('path')
const Disposable = require('promise-toolbox/Disposable')
const min = require('lodash/min')

const { getVmBackupDir } = require('../_getVmBackupDir.js')
const { RemoteAdapter } = require('../RemoteAdapter.js')

const { CLEAN_VM_QUEUE } = require('./index.js')

// -------------------------------------------------------------------

catchGlobalErrors(createLogger('xo:backups:mergeWorker'))

const { fatal, info, warn } = createLogger('xo:backups:mergeWorker')

// -------------------------------------------------------------------

const main = Disposable.wrap(async function* main(args) {
  const handler = yield getSyncedHandler({ url: 'file://' + process.cwd() })

  yield handler.lock(CLEAN_VM_QUEUE)

  const adapter = new RemoteAdapter(handler)

  const listRetry = async () => {
    const timeoutResolver = resolve => setTimeout(resolve, 10e3)
    for (let i = 0; i < 10; ++i) {
      const entries = await handler.list(CLEAN_VM_QUEUE)
      if (entries.length !== 0) {
        return entries
      }
      await new Promise(timeoutResolver)
    }
  }

  let taskFiles
  while ((taskFiles = await listRetry()) !== undefined) {
    const taskFileBasename = min(taskFiles)
    const taskFile = join(CLEAN_VM_QUEUE, '_' + taskFileBasename)

    // move this task to the end
    await handler.rename(join(CLEAN_VM_QUEUE, taskFileBasename), taskFile)
    try {
      const vmDir = getVmBackupDir(String(await handler.readFile(taskFile)))
      try {
        await adapter.cleanVm(vmDir, { merge: true, onLog: info, remove: true })
      } catch (error) {
        // consider the clean successful if the VM dir is missing
        if (error.code !== 'ENOENT') {
          throw error
        }
      }

      handler.unlink(taskFile).catch(error => warn('deleting task failure', { error }))
    } catch (error) {
      warn('failure handling task', { error })
    }
  }
})

info('starting')
main(process.argv.slice(2)).then(
  () => {
    info('bye :-)')
  },
  error => {
    fatal(error)

    process.exit(1)
  }
)
<commit_msg>fix(backups/merge-worker): handle ENAMETOOLONG errors<commit_after>#!/usr/bin/env node

const { catchGlobalErrors } = require('@xen-orchestra/log/configure.js')
const { createLogger } = require('@xen-orchestra/log')
const { getSyncedHandler } = require('@xen-orchestra/fs')
const { join } = require('path')
const Disposable = require('promise-toolbox/Disposable')
const min = require('lodash/min')

const { getVmBackupDir } = require('../_getVmBackupDir.js')
const { RemoteAdapter } = require('../RemoteAdapter.js')

const { CLEAN_VM_QUEUE } = require('./index.js')

// -------------------------------------------------------------------

catchGlobalErrors(createLogger('xo:backups:mergeWorker'))

const { fatal, info, warn } = createLogger('xo:backups:mergeWorker')

// -------------------------------------------------------------------

const main = Disposable.wrap(async function* main(args) {
  const handler = yield getSyncedHandler({ url: 'file://' + process.cwd() })

  yield handler.lock(CLEAN_VM_QUEUE)

  const adapter = new RemoteAdapter(handler)

  const listRetry = async () => {
    const timeoutResolver = resolve => setTimeout(resolve, 10e3)
    for (let i = 0; i < 10; ++i) {
      const entries = await handler.list(CLEAN_VM_QUEUE)
      if (entries.length !== 0) {
        return entries
      }
      await new Promise(timeoutResolver)
    }
  }

  let taskFiles
  while ((taskFiles = await listRetry()) !== undefined) {
    const taskFileBasename = min(taskFiles)
    const previousTaskFile = join(CLEAN_VM_QUEUE, taskFileBasename)
    const taskFile = join(CLEAN_VM_QUEUE, '_' + taskFileBasename)

    // move this task to the end
    try {
      await handler.rename(previousTaskFile, taskFile)
    } catch (error) {
      // this error occurs if the task failed too many times (i.e. too many `_` prefixes)
      // there is nothing more that can be done
      if (error.code === 'ENAMETOOLONG') {
        await handler.unlink(previousTaskFile)
      }

      throw error
    }

    try {
      const vmDir = getVmBackupDir(String(await handler.readFile(taskFile)))
      try {
        await adapter.cleanVm(vmDir, { merge: true, onLog: info, remove: true })
      } catch (error) {
        // consider the clean successful if the VM dir is missing
        if (error.code !== 'ENOENT') {
          throw error
        }
      }

      handler.unlink(taskFile).catch(error => warn('deleting task failure', { error }))
    } catch (error) {
      warn('failure handling task', { error })
    }
  }
})

info('starting')
main(process.argv.slice(2)).then(
  () => {
    info('bye :-)')
  },
  error => {
    fatal(error)

    process.exit(1)
  }
)
<|endoftext|>


<commit_before>// Make requests to Twitter
var Twitter = (function ()  {
  var my = {};

  // Make a GET request.
  my.get = function(path, callback, parameters) {
    my.http('GET', path, callback, parameters);
  }

  // Make a POST request.
  my.post = function(path, callback, parameters) {
    my.http('POST', path, callback, parameters);
  }

  // Makes the HTTP request to Twitter. Don't call directly.
  my.http = function(method, path, callback, params) {
    parameters = {method: method};
    if (params) {
      parameters.parameters = params;
    }
    // Decode the JSON response.
    var callbackWrapper = function(data, xhr) {

      if (xhr.status != 200 && xhr.status >= 500) {
        callback({data: data, status: xhr.status})
      } else {
        callback({data:JSON.parse(data), status: xhr.status});
      }
    }
    oauth.sendSignedRequest(my.buildUrl(path), callbackWrapper, parameters);
  }

  // Take the Twitter API path and build full API URL.
  my.buildUrl = function(path) {
    return 'https://api.twitter.com/1/' + path + '.json';
  }

  return my;
}());<commit_msg>added mentions and direct_messages methods to Twitter.<commit_after>// Make requests to Twitter
var Twitter = (function ()  {
  var my = {};
  my.current_requests = {mentions: false, direct_messages: false};

  // Get mentions
  my.mentions = function(init) {
    if (my.current_requests.mentions) {
      return false;
    }
    var callback = function(result) {
      if (200 == result.status && result.data.length){
        localStorage.statuses_last_id = result.data[0].id;
        for(var status in result.data) {
          Status.save(result.data[status]);
          Notice.status(result.data[status].id);
        }
      }
      my.current_requests.mentions = false;
      console.log('Pulled new mentions :)');
    };
    var parameters = {};
    if (localStorage.statuses_last_id) {
      parameters.since_id = localStorage.statuses_last_id;
    }
    // Make request to Twitter for mentions.
    Twitter.get('statuses/mentions', callback, parameters);
  }

  // Get direct messages
  my.direct_messages = function(init) {
    if (my.current_requests.direct_messages) {
      return false;
    }
    var callback = function(result) {
      if (200 == result.status && result.data.length){
        localStorage.direct_messages_last_id = result.data[0].id;
        for(var direct_messages in result.data) {
          DirectMessage.save(result.data[direct_messages]);
          Notice.direct_message(result.data[direct_messages].id);
        }
      }
      my.current_requests.direct_messages = false;
      console.log('Pulled new direct message :)');
    };
    var parameters = {};
    if (localStorage.direct_messages_last_id) {
      parameters.since_id = localStorage.direct_messages_last_id;
    }
    // Make request to Twitter for direct messages.
    Twitter.get('direct_messages', callback, parameters);
  }

  // Make a GET request.
  my.get = function(path, callback, parameters) {
    my.http('GET', path, callback, parameters);
  }

  // Make a POST request.
  my.post = function(path, callback, parameters) {
    my.http('POST', path, callback, parameters);
  }

  // Makes the HTTP request to Twitter. Don't call directly.
  my.http = function(method, path, callback, params) {
    parameters = {method: method};
    if (params) {
      parameters.parameters = params;
    }
    // Decode the JSON response.
    var callbackWrapper = function(data, xhr) {

      if (xhr.status != 200 && xhr.status >= 500) {
        callback({data: data, status: xhr.status})
      } else {
        callback({data:JSON.parse(data), status: xhr.status});
      }
    }
    oauth.sendSignedRequest(my.buildUrl(path), callbackWrapper, parameters);
  }

  // Take the Twitter API path and build full API URL.
  my.buildUrl = function(path) {
    return 'https://api.twitter.com/1/' + path + '.json';
  }

  return my;
}());<|endoftext|>