<commit_before>angular.module("yds").factory("PValues", [
    function () {
        const CATEGORICAL = "c";
        const NUMERICAL = "n";

        const MAX_RES_SAMPLE_SIZE = 10;
        const MAX_HIST_BINS = 100;
        const MAX_SEARCH_SAMPLE_SIZE = 1000;
        const MAX_HIST_SAMPLE_SIZE = 10000;

        /**
         * Create a 2D array with the specified initial value
         * @param x Number of rows
         * @param y Number of columns
         * @param defaultValue  Default value
         * @returns {Array}
         */
        var twoDimArray = function (x, y, defaultValue) {
            var array = new Array(x);

            for (var i = 0; i < x; i++) {
                array[i] = new Array(y);
                array[i].fill(defaultValue);
            }

            return array;
        };

        /**
         * Count the different values that appear in an array of items
         * @param data  Array of items
         * @returns {number}    Number of different values
         */
        var countDifferentValues = function (data) {
            var count = 0;
            var seenValues = [];

            _.each(data, function (value) {
                if (seenValues.indexOf(value) === -1) {
                    seenValues.push(value);
                    count++;
                }
            });
            // console.log(seenValues);
            return count;
        };

        var calcRes = function (values) {
            var res = Number.POSITIVE_INFINITY;
            var mod = Math.max(1, parseInt(values.length / MAX_RES_SAMPLE_SIZE));
            // console.log("\tmod:", mod);
            for (var i = 0; i < values.length; i += mod) {
                var valI = values[i];
                for (var j = 0; j < values.length; j++) {
                    var valJ = values[j];

                    var diff = Math.abs(valJ - valI);
                    if (diff > 0) {
                        // var resOld = res;
                        res = Math.min(res, diff);
                        // if (resOld !== res)
                        //     console.log("res is now: ", res, "(diff:", diff, ") vals: ", valI, valJ);
                    }
                }
            }
            return Math.max(res, 1.0 / MAX_HIST_BINS);
        };

        var constrainNumber = function (val, min, max) {
            return (val < min) ? min : ((val > max) ? max : val);
        };

        var hist2D = function (dataA, dataB, bNumX, bNumY) {
            var counts = twoDimArray(bNumX, bNumY, 0.0);
            var valueW = 1; // We don't handle values with weights, assuming all weights as 1.0.

            // Check the assumption that dataA.length == dataB.length
            if (dataA.length !== dataB.length) {
                console.error("Error: Different lengths!");
                return counts;
            }
            var numOfValues = dataA.length;

            var bsizex = 1.0 / bNumX;
            var bsizey = 1.0 / bNumY;
            var mod = Math.max(1.0, numOfValues / MAX_HIST_SAMPLE_SIZE);

            for (var i = 0; i < numOfValues; i += mod) {
                var binx = constrainNumber(dataA[i] / bsizex, 0, bNumX - 1);
                var biny = constrainNumber(dataB[i] / bsizey, 0, bNumY - 1);
                counts[binx][biny] += valueW;
            }

            return counts;
        };

        var countsMeanDev = function (counts) {
            var ni = counts.length;
            var nj = counts[0].length;
            var n = ni * nj;
            var sum = 0;
            var sumsq = 0;
            for (var i = 0; i < ni; i++) {
                for (var j = 0; j < nj; j++) {
                    var count = counts[i][j];
                    sum += count;
                    sumsq += count * count;
                }
            }

            var mean = sum / n;
            var meansq = sumsq / n;
            var dev = Math.max(0, meansq - mean * mean);
            return [mean, dev];
        };

        var poissonCost = function (n, h, counts) {
            var res = countsMeanDev(counts);
            var k = res[0];
            var v = res[1];

            return (2 * k - v) / (n * n * h * h);   // cost
        };

        /**
         * Transform a categorical variable to numbers, ranging from 0 to the number of
         * different values that appear.
         * @param data      Data to transform
         * @returns {Array} Transformed data
         */
        var categoricalToNum = function (data) {
            var newData = [];

            var count = 0;
            var index = {};

            _.each(data, function (value) {
                if (!_.has(index, value)) {
                    index[value] = count;
                    count++;
                }
                newData.push(index[value]);
            });

            return newData;
        };

        /**
         * Normalize an array of numbers so that the maximum value is 1.0.
         * @param array Array of numbers
         */
        var normalizeArray = function (array) {
            var ratio = Math.max.apply(Math, array); // (divided by maximum value, here 1.0)

            return array.map(function (num) {
                return num / ratio;
            });
        };

        /**
         * Optimal histogram bin size calculation (???)
         * @param dataA Variable A data
         * @param typeA Variable A type
         * @param dataB Variable B data
         * @param typeB Variable B type
         * @param algorithm Algorithm to use
         * @returns {[number,number]} Number of bins for each variable
         */
        var binOptimizer = function (dataA, typeA, dataB, typeB, algorithm) {
            var countA = (typeA === CATEGORICAL) ? countDifferentValues(dataA) : Math.max.apply(Math, dataA) + 1;
            var countB = (typeB === CATEGORICAL) ? countDifferentValues(dataB) : Math.max.apply(Math, dataB) + 1;
            // Above seems more correct, but mirador parsing thinks # of tattoos is categorical so results are different
            // var countA = countDifferentValues(dataA);
            // var countB = countDifferentValues(dataB);
            // console.log("counts: ", countA, countB);

            if (typeA === CATEGORICAL && typeB === CATEGORICAL) {
                // Return the number of different answers
                return [countA, countB];
            }

            // Turn categorical values into numbers, or parse the values of numerical variables as floats
            if (typeA === CATEGORICAL) {
                dataA = categoricalToNum(dataA);
            } else {
                dataA = dataA.map(parseFloat);
            }
            if (typeB === CATEGORICAL) {
                dataB = categoricalToNum(dataB);
            } else {
                dataB = dataB.map(parseFloat);
            }

            var size = dataA.length;
            var sqSize = parseInt(Math.sqrt(size / 2));
            var lcount, icount, res;

            var minNBins0, maxNBins0;
            if (typeA === CATEGORICAL || countA < 5) {
                minNBins0 = maxNBins0 = countA;
            } else {
                minNBins0 = 2;
                lcount = countA;
                // console.log("lcount (A)", lcount);
                if (_.has(Number, "MAX_SAFE_INTEGER")) {
                    icount = Number.MAX_SAFE_INTEGER < lcount ? Number.MAX_SAFE_INTEGER : lcount;
                } else {
                    icount = lcount;
                }

                res = calcRes(normalizeArray(dataA));
                maxNBins0 = Math.min(Math.round(1.0 / res), icount, sqSize);
            }

            var minNBins1, maxNBins1;
            if (typeB === CATEGORICAL || countB < 5) {
                minNBins1 = maxNBins1 = countB;
            } else {
                minNBins1 = 2;
                lcount = countB;
                // console.log("lcount (B)", lcount);
                if (_.has(Number, "MAX_SAFE_INTEGER")) {
                    icount = Number.MAX_SAFE_INTEGER < lcount ? Number.MAX_SAFE_INTEGER : lcount;
                } else {
                    icount = lcount;
                }

                res = calcRes(normalizeArray(dataB));
                // console.log("resy", res);
                maxNBins1 = Math.min(Math.round(1.0 / res), icount, sqSize);
            }

            // console.log("Min bins:", minNBins0, "/", minNBins1);
            // console.log("Max bins:", maxNBins0, "/", maxNBins1);

            //todo: check for rice/scott algorithms here?

            var blen0 = maxNBins0 - minNBins0 + 1;
            var blen1 = maxNBins1 - minNBins1 + 1;
            var numValues = blen0 * blen1;

            if (minNBins0 <= 0 || maxNBins0 <= 0 || blen0 <= 0 || minNBins1 <= 0 || maxNBins1 <= 0 || blen1 <= 0) {
                console.error("Unexpected number of bins");
                return [1, 1];
            }

            var minn0 = (minNBins0 + maxNBins0) / 2;
            var minn1 = (minNBins1 + maxNBins1) / 2;
            var minc = Number.MAX_VALUE;
            var mod = Math.max(1, numValues / MAX_SEARCH_SAMPLE_SIZE);

            for (var i = 0; i < numValues; i += mod) {
                var n0 = parseInt(i / blen1) + minNBins0;   // Make sure it's an integer
                var n1 = i % blen1 + minNBins1;

                var bsize0 = 1.0 / n0;
                var bsize1 = 1.0 / n1;
                var barea = bsize0 * bsize1;
                var counts = hist2D(dataA, dataB, n0, n1);

                var c = 0;
                // Poisson method
                c = poissonCost(size, barea, counts);
                //todo: check for crossval algorithm here?

                if (c < minc) {
                    minc = c;
                    minn0 = n0;
                    minn1 = n1;
                }
            }

            return [minn0, minn1];
        };

        /**
         * Calculate the PValues
         */
        var calculatePValues = function (variables, data) {
            var varNames = variables.map(_.first);
            var varsNum = varNames.length;

            // Gather the types of the variables into an object instead of an array as given
            var varTypes = {};
            _.each(variables, function (varArray) {
                varTypes[varArray[0]] = varArray[1];
            });

            // Initialize the two-dimensional array with -1 as values
            var pValues = twoDimArray(varsNum, varsNum, -1);

            // Extract the data for each variable, since we will need all of them
            var count = data.length;
            var varData = {};
            _.each(varNames, function (name) {
                varData[name] = _.pluck(data, name);
            });

            // Calculate the p values
            _.each(varNames, function (varA, i) {
                // Get variable data & type
                var dataA = varData[varA];
                var typeA = varTypes[varA];

                _.each(varNames, function (varB, j) {
                    if (pValues[i][j] > -1) return; // Move on, score exists
                    console.log("\nFinding correlation of", varA, "and", varB);

                    // Get variable data & type
                    var dataB = varData[varB];
                    var typeB = varTypes[varB];

                    var res = binOptimizer(dataA, typeA, dataB, typeB, "??");
                    console.log("bins: ", res);

                    //todo: find actual p value
                    pValues[i][j] = 0.01;
                    pValues[j][i] = 0.01;
                });
            });

            return pValues;
        };

        return {
            calculate: calculatePValues
        }
    }
]);
<commit_msg>Calculate mutual information<commit_after>angular.module("yds").factory("PValues", [
    function () {
        const CATEGORICAL = "c";
        const NUMERICAL = "n";

        const MAX_RES_SAMPLE_SIZE = 10;
        const MAX_HIST_BINS = 100;
        const MAX_SEARCH_SAMPLE_SIZE = 1000;
        const MAX_HIST_SAMPLE_SIZE = 10000;

        /**
         * Create a 2D array with the specified initial value
         * @param x Number of rows
         * @param y Number of columns
         * @param defaultValue  Default value
         * @returns {Array}
         */
        var twoDimArray = function (x, y, defaultValue) {
            var array = new Array(x);

            for (var i = 0; i < x; i++) {
                array[i] = new Array(y);
                array[i].fill(defaultValue);
            }

            return array;
        };

        /**
         * Count the different values that appear in an array of items
         * @param data  Array of items
         * @returns {number}    Number of different values
         */
        var countDifferentValues = function (data) {
            var count = 0;
            var seenValues = [];

            _.each(data, function (value) {
                if (seenValues.indexOf(value) === -1) {
                    seenValues.push(value);
                    count++;
                }
            });
            // console.log(seenValues);
            return count;
        };

        var calcRes = function (values) {
            var res = Number.POSITIVE_INFINITY;
            var mod = Math.max(1, parseInt(values.length / MAX_RES_SAMPLE_SIZE));
            // console.log("\tmod:", mod);
            for (var i = 0; i < values.length; i += mod) {
                var valI = values[i];
                for (var j = 0; j < values.length; j++) {
                    var valJ = values[j];

                    var diff = Math.abs(valJ - valI);
                    if (diff > 0) {
                        // var resOld = res;
                        res = Math.min(res, diff);
                        // if (resOld !== res)
                        //     console.log("res is now: ", res, "(diff:", diff, ") vals: ", valI, valJ);
                    }
                }
            }
            return Math.max(res, 1.0 / MAX_HIST_BINS);
        };

        var constrainNumber = function (val, min, max) {
            return (val < min) ? min : ((val > max) ? max : val);
        };

        var hist2D = function (dataA, dataB, bNumX, bNumY) {
            var counts = twoDimArray(bNumX, bNumY, 0.0);
            var valueW = 1; // We don't handle values with weights, assuming all weights as 1.0.

            // Check the assumption that dataA.length == dataB.length
            if (dataA.length !== dataB.length) {
                console.error("Error: Different lengths!");
                return counts;
            }
            var numOfValues = dataA.length;

            var bsizex = 1.0 / bNumX;
            var bsizey = 1.0 / bNumY;
            var mod = Math.max(1.0, numOfValues / MAX_HIST_SAMPLE_SIZE);

            for (var i = 0; i < numOfValues; i += mod) {
                var binx = constrainNumber(dataA[i] / bsizex, 0, bNumX - 1);
                var biny = constrainNumber(dataB[i] / bsizey, 0, bNumY - 1);
                counts[binx][biny] += valueW;
            }

            return counts;
        };

        var countsMeanDev = function (counts) {
            var ni = counts.length;
            var nj = counts[0].length;
            var n = ni * nj;
            var sum = 0;
            var sumsq = 0;
            for (var i = 0; i < ni; i++) {
                for (var j = 0; j < nj; j++) {
                    var count = counts[i][j];
                    sum += count;
                    sumsq += count * count;
                }
            }

            var mean = sum / n;
            var meansq = sumsq / n;
            var dev = Math.max(0, meansq - mean * mean);
            return [mean, dev];
        };

        var poissonCost = function (n, h, counts) {
            var res = countsMeanDev(counts);
            var k = res[0];
            var v = res[1];

            return (2 * k - v) / (n * n * h * h);   // cost
        };

        /**
         * Transform a categorical variable to numbers, ranging from 0 to the number of
         * different values that appear.
         * @param data      Data to transform
         * @returns {Array} Transformed data
         */
        var categoricalToNum = function (data) {
            var newData = [];

            var count = 0;
            var index = {};

            _.each(data, function (value) {
                if (!_.has(index, value)) {
                    index[value] = count;
                    count++;
                }
                newData.push(index[value]);
            });

            return newData;
        };

        /**
         * Normalize an array of numbers so that the maximum value is 1.0.
         * @param array Array of numbers
         */
        var normalizeArray = function (array) {
            var ratio = Math.max.apply(Math, array); // (divided by maximum value, here 1.0)

            return array.map(function (num) {
                return num / ratio;
            });
        };

        /**
         * Optimal histogram bin size calculation (???)
         * @param dataA Variable A data
         * @param typeA Variable A type
         * @param dataB Variable B data
         * @param typeB Variable B type
         * @param algorithm Algorithm to use
         * @returns {[number,number]} Number of bins for each variable
         */
        var binOptimizer = function (dataA, typeA, dataB, typeB, algorithm) {
            var countA = (typeA === CATEGORICAL) ? countDifferentValues(dataA) : Math.max.apply(Math, dataA) + 1;
            var countB = (typeB === CATEGORICAL) ? countDifferentValues(dataB) : Math.max.apply(Math, dataB) + 1;
            // Above seems more correct, but mirador parsing thinks # of tattoos is categorical so results are different
            // var countA = countDifferentValues(dataA);
            // var countB = countDifferentValues(dataB);
            // console.log("counts: ", countA, countB);

            if (typeA === CATEGORICAL && typeB === CATEGORICAL) {
                // Return the number of different answers
                return [countA, countB];
            }

            var size = dataA.length;
            var sqSize = parseInt(Math.sqrt(size / 2));
            var lcount, icount, res;

            var minNBins0, maxNBins0;
            if (typeA === CATEGORICAL || countA < 5) {
                minNBins0 = maxNBins0 = countA;
            } else {
                minNBins0 = 2;
                lcount = countA;
                // console.log("lcount (A)", lcount);
                if (_.has(Number, "MAX_SAFE_INTEGER")) {
                    icount = Number.MAX_SAFE_INTEGER < lcount ? Number.MAX_SAFE_INTEGER : lcount;
                } else {
                    icount = lcount;
                }

                res = calcRes(normalizeArray(dataA));
                maxNBins0 = Math.min(Math.round(1.0 / res), icount, sqSize);
            }

            var minNBins1, maxNBins1;
            if (typeB === CATEGORICAL || countB < 5) {
                minNBins1 = maxNBins1 = countB;
            } else {
                minNBins1 = 2;
                lcount = countB;
                // console.log("lcount (B)", lcount);
                if (_.has(Number, "MAX_SAFE_INTEGER")) {
                    icount = Number.MAX_SAFE_INTEGER < lcount ? Number.MAX_SAFE_INTEGER : lcount;
                } else {
                    icount = lcount;
                }

                res = calcRes(normalizeArray(dataB));
                // console.log("resy", res);
                maxNBins1 = Math.min(Math.round(1.0 / res), icount, sqSize);
            }

            // console.log("Min bins:", minNBins0, "/", minNBins1);
            // console.log("Max bins:", maxNBins0, "/", maxNBins1);

            //todo: check for rice/scott algorithms here?

            var blen0 = maxNBins0 - minNBins0 + 1;
            var blen1 = maxNBins1 - minNBins1 + 1;
            var numValues = blen0 * blen1;

            if (minNBins0 <= 0 || maxNBins0 <= 0 || blen0 <= 0 || minNBins1 <= 0 || maxNBins1 <= 0 || blen1 <= 0) {
                console.error("Unexpected number of bins");
                return [1, 1];
            }

            var minn0 = (minNBins0 + maxNBins0) / 2;
            var minn1 = (minNBins1 + maxNBins1) / 2;
            var minc = Number.MAX_VALUE;
            var mod = Math.max(1, numValues / MAX_SEARCH_SAMPLE_SIZE);

            for (var i = 0; i < numValues; i += mod) {
                var n0 = parseInt(i / blen1) + minNBins0;   // Make sure it's an integer
                var n1 = i % blen1 + minNBins1;

                var bsize0 = 1.0 / n0;
                var bsize1 = 1.0 / n1;
                var barea = bsize0 * bsize1;
                var counts = hist2D(dataA, dataB, n0, n1);

                var c = 0;
                // Poisson method
                c = poissonCost(size, barea, counts);
                //todo: check for crossval algorithm here?

                if (c < minc) {
                    minc = c;
                    minn0 = n0;
                    minn1 = n1;
                }
            }

            return [minn0, minn1];
        };

        /**
         * Round a number to the specified number of places.
         * From: https://stackoverflow.com/a/12830454
         * @param num
         * @param scale
         * @returns {number}
         */
        var roundNumber = function (num, scale) {
            if (!("" + num).includes("e")) {
                return +(Math.round(num + "e+" + scale) + "e-" + scale);
            } else {
                var arr = ("" + num).split("e");
                var sig = "";
                if (+arr[1] + scale > 0) {
                    sig = "+";
                }
                return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
            }
        };

        var mutualInformation = function (dataA, typeA, dataB, typeB, nbinx, nbiny) {
            if (nbinx < 2 || nbiny < 2)
                return 0;

            var sbinx = roundNumber(1.0 / nbinx, 8),
                sbiny = roundNumber(1.0 / nbiny, 8);
            // console.log("sbins: ", sbinx, sbiny);

            var countsx = new Array(nbinx),
                countsy = new Array(nbiny),
                counts = twoDimArray(nbinx, nbiny, 0);

            // Fill countsx & countsy with zeros
            countsx.fill(0);
            countsy.fill(0);

            var singlebx = true,
                singleby = true,
                lastbx = -1,
                lastby = -1,
                total = 0,
                valueW = 1.0;   // We don't have weights, using 1.0 as weight always

            var bx, by;
            for (var i = 0; i < dataA.length; i++) {
                var valX = dataA[i];
                var valY = dataB[i];

                bx = Math.floor(Math.min(valX / sbinx, nbinx - 1));
                by = Math.floor(Math.min(valY / sbiny, nbiny - 1));
                // console.log("\tbx, by", bx, by);

                if (bx < 0 || by < 0) {
                    console.error("A bin index is negative:", bx, nbinx, "|", by, nbiny);
                    continue;
                }

                counts[bx][by] += valueW;
                countsx[bx] += valueW;
                countsy[by] += valueW;

                if (lastbx !== -1 && lastbx !== bx) {
                    singlebx = false;
                }
                if (lastby !== -1 && lastby !== by) {
                    singleby = false;
                }

                lastbx = bx;
                lastby = by;
                total += valueW;
            }

            // Pairs with only 1 occupied bin are considered independent
            if (singlebx || singleby) {
                return 0;
            }

            var information = 0;
            var nonzero = 0;
            for (bx = 0; bx < nbinx; bx++) {
                var px = countsx[bx] / total;
                for (by = 0; by < nbiny; by++) {
                    var pxy = counts[bx][by] / total;
                    var py = countsy[by] / total;

                    var ibin = 0;
                    if (pxy > 0 && px > 0 && py > 0) {
                        nonzero++;
                        ibin = pxy * (Math.log(pxy / (px * py)));
                    }

                    information += ibin;
                }
            }

            if (information < 0 || _.isNaN(information)) {
                return 0;
            }

            // Finite size correction
            var correction = (nonzero - nbinx - nbiny + 1) / (2 * total);
            // console.log("Information:", information);
            // console.log("Correction:", correction);
            return Math.max(0, information - correction);
        };

        /**
         * Calculate the PValues
         */
        var calculatePValues = function (variables, data) {
            var varNames = variables.map(_.first);
            var varsNum = varNames.length;

            // Gather the types of the variables into an object instead of an array as given
            var varTypes = {};
            _.each(variables, function (varArray) {
                varTypes[varArray[0]] = varArray[1];
            });

            // Initialize the two-dimensional array with -1 as values
            var pValues = twoDimArray(varsNum, varsNum, -1);

            // Extract the data for each variable, since we will need all of them
            var count = data.length;
            var varData = {};
            _.each(varNames, function (name) {
                varData[name] = _.pluck(data, name);
            });

            // Calculate the p values
            _.each(varNames, function (varA, i) {
                // Get variable data & type
                var dataA = varData[varA];
                var typeA = varTypes[varA];

                _.each(varNames, function (varB, j) {
                    if (pValues[i][j] > -1) return; // Move on, score exists
                    console.log("\nFinding correlation of", varA, "and", varB);

                    // Get variable data & type
                    var dataB = varData[varB];
                    var typeB = varTypes[varB];

                    // Turn categorical values into numbers, or parse the values of numerical variables as floats
                    if (typeA === CATEGORICAL) {
                        dataA = categoricalToNum(dataA);
                    } else {
                        dataA = dataA.map(parseFloat);
                    }
                    if (typeB === CATEGORICAL) {
                        dataB = categoricalToNum(dataB);
                    } else {
                        dataB = dataB.map(parseFloat);
                    }

                    var res = binOptimizer(dataA, typeA, dataB, typeB, "??");
                    var binx = res[0];
                    var biny = res[1];
                    console.log("Bins:", binx, ",", biny);

                    if (binx < 2 || biny < 2) {
                        // Set pvalue to 1 and continue
                        pValues[i][j] = 1;
                        pValues[j][i] = 1;
                        return;
                    }

                    // Calculate mutual information
                    var ixy = mutualInformation(
                        (typeA === NUMERICAL) ? normalizeArray(dataA) : dataA,
                        typeA,
                        (typeB === NUMERICAL) ? normalizeArray(dataB) : dataB,
                        typeB,
                        binx,
                        biny);
                    console.log("Mutual info:", ixy);
                    var pval = 0;

                    if (varA === varB) {
                        // Set pvalue to 0 and continue
                        pValues[i][j] = pval;
                        pValues[j][i] = pval;
                        return;
                    }

                    //todo: dependency checks here

                    pValues[i][j] = pval;
                    pValues[j][i] = pval;
                });
            });
            console.log("CALCULATIONS DONE!");
            return pValues;
        };

        return {
            calculate: calculatePValues
        }
    }
]);
<|endoftext|>


<commit_before>/* eslint-disable object-shorthand */

// NOTE: Copied from spectacle

const defaultColors = {
  primary: "#f9c300",
  secondary: "black",
  tertiary: "white",
  quartenary: "white"
};

const defaultFonts = {
  primary: "Open Sans",
  secondary: "Lobster Two",
  tertiary: "monospace"
};

const screen = (colorArgs = defaultColors, fontArgs = defaultFonts) => {
  const colors = Object.assign({}, defaultColors, colorArgs);
  const fonts = Object.assign({}, defaultFonts, fontArgs);
  return {
    colors: colors,
    fonts: fonts,
    global: {
      body: {
        background: colors.primary,
        fontFamily: fonts.primary,
        fontWeight: "normal",
        fontSize: "2em",
        color: colors.secondary,
        overflow: "hidden"
      },
      "html, body": {
        height: "100%"
      },
      "*": {
        boxSizing: "border-box"
      }
    },
    fullscreen: {
      fill: colors.tertiary
    },
    controls: {
      prev: {
        position: "absolute",
        top: "50%",
        left: 20,
        transform: "translateY(-50%)",
        zIndex: 9999,
        background: "none",
        border: "none",
        outline: 0
      },
      prevIcon: {
        fill: colors.quartenary
      },
      next: {
        position: "absolute",
        top: "50%",
        right: 20,
        transform: "translateY(-50%)",
        zIndex: 9999,
        background: "none",
        border: "none",
        outline: 0
      },
      nextIcon: {
        fill: colors.quartenary
      }
    },
    progress: {
      pacman: {
        container: {
          position: "absolute",
          bottom: "5px",
          left: "50%",
          transition: "all 1s ease-in-out 0.2s",
          zIndex: 1000
        },
        pacman: {
          position: "absolute",
          transition: "left 0.3s ease-in-out 0.2s",
          width: "20px",
          height: "20px",
          transform: "translate(-5px, -5px)"
        },
        pacmanTop: {
          position: "absolute",
          content: " ",
          width: "20px",
          height: "10px",
          borderTopLeftRadius: "10px",
          borderTopRightRadius: "10px",
          background: colors.quartenary
        },
        pacmanBottom: {
          position: "absolute",
          content: " ",
          width: "20px",
          height: "10px",
          borderBottomLeftRadius: "10px",
          borderBottomRightRadius: "10px",
          background: colors.quartenary,
          top: "10px"
        },
        point: {
          position: "absolute",
          float: "left",
          background: "transparent",
          width: "10px",
          height: "10px",
          borderWidth: 2,
          borderStyle: "solid",
          borderColor: colors.quartenary,
          borderRadius: "50%",
          transition: "all 0.01s ease-out 0.4s"
        }
      },
      bar: {
        container: {
          position: "absolute",
          height: "10px",
          width: "100%",
          bottom: 0,
          left: 0,
          transition: "all 1s ease-in-out 0.2s",
          zIndex: 1000
        },
        bar: {
          height: "100%",
          background: colors.quartenary,
          transition: "all 0.3s ease-out"
        }
      },
      number: {
        container: {
          position: "absolute",
          bottom: 10,
          right: 10,
          zIndex: 1000,
          color: colors.quartenary
        }
      }
    },
    components: {
      blockquote: {
        textAlign: "left",
        position: "relative",
        display: "inline-block",
        margin: 0
      },
      quote: {
        borderLeft: `1px solid ${colors.primary}`,
        paddingLeft: 40,
        display: "block",
        color: colors.primary,
        fontSize: "4.9rem",
        lineHeight: 1,
        fontWeight: "bold"
      },
      cite: {
        color: colors.tertiary,
        display: "block",
        clear: "left",
        fontSize: "2rem",
        marginTop: 0
      },
      content: {
        margin: "0 auto",
        textAlign: "center"
      },
      codePane: {
        pre: {
          margin: "auto",
          fontSize: "0.8rem",
          fontWeight: "normal",
          fontFamily: fonts.tertiary,
          minWidth: "100%",
          maxWidth: 800
        },
        code: {
          textAlign: "left",
          fontWeight: "normal"
        }
      },
      code: {
        color: "black",
        fontSize: "2.66rem",
        fontFamily: fonts.tertiary,
        margin: 0,
        backgroundColor: "rgba(0,0,0,0.15)",
        padding: "0 10px",
        borderRadius: 3
      },
      heading: {
        h1: {
          color: colors.tertiary,
          fontSize: "7.05rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0,
          zoom: 1
        },
        h2: {
          color: colors.secondary,
          fontSize: "5.88rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h3: {
          color: "black",
          fontSize: "4.9rem",
          fontFamily: fonts.secondary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h4: {
          color: "black",
          fontSize: "3.82rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h5: {
          color: "black",
          fontSize: "3.19rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h6: {
          color: "black",
          fontSize: "2.66rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        }
      },
      image: {
        display: "block",
        margin: 0
      },
      link: {
        textDecoration: "none"
      },
      listItem: {
        fontSize: "2.66rem"
      },
      list: {
        textAlign: "left",
        listStylePosition: "inside",
        padding: 0
      },
      s: {
        strikethrough: {}
      },
      tableHeaderItem: {
        fontSize: "2.66rem",
        fontWeight: "bold"
      },
      tableItem: {
        fontSize: "2.66rem"
      },
      table: {
        width: "100%"
      },
      text: {
        color: "black",
        fontSize: "2.66rem",
        fontFamily: fonts.primary,
        margin: 0
      }
    }
  };
};

export default screen;
<commit_msg>Revert "change name of font in themes"<commit_after>/* eslint-disable object-shorthand */

// NOTE: Copied from spectacle

const defaultColors = {
  primary: "#f9c300",
  secondary: "black",
  tertiary: "white",
  quartenary: "white"
};

const defaultFonts = {
  primary: "Open Sans Condensed",
  secondary: "Lobster Two",
  tertiary: "monospace"
};

const screen = (colorArgs = defaultColors, fontArgs = defaultFonts) => {
  const colors = Object.assign({}, defaultColors, colorArgs);
  const fonts = Object.assign({}, defaultFonts, fontArgs);
  return {
    colors: colors,
    fonts: fonts,
    global: {
      body: {
        background: colors.primary,
        fontFamily: fonts.primary,
        fontWeight: "normal",
        fontSize: "2em",
        color: colors.secondary,
        overflow: "hidden"
      },
      "html, body": {
        height: "100%"
      },
      "*": {
        boxSizing: "border-box"
      }
    },
    fullscreen: {
      fill: colors.tertiary
    },
    controls: {
      prev: {
        position: "absolute",
        top: "50%",
        left: 20,
        transform: "translateY(-50%)",
        zIndex: 9999,
        background: "none",
        border: "none",
        outline: 0
      },
      prevIcon: {
        fill: colors.quartenary
      },
      next: {
        position: "absolute",
        top: "50%",
        right: 20,
        transform: "translateY(-50%)",
        zIndex: 9999,
        background: "none",
        border: "none",
        outline: 0
      },
      nextIcon: {
        fill: colors.quartenary
      }
    },
    progress: {
      pacman: {
        container: {
          position: "absolute",
          bottom: "5px",
          left: "50%",
          transition: "all 1s ease-in-out 0.2s",
          zIndex: 1000
        },
        pacman: {
          position: "absolute",
          transition: "left 0.3s ease-in-out 0.2s",
          width: "20px",
          height: "20px",
          transform: "translate(-5px, -5px)"
        },
        pacmanTop: {
          position: "absolute",
          content: " ",
          width: "20px",
          height: "10px",
          borderTopLeftRadius: "10px",
          borderTopRightRadius: "10px",
          background: colors.quartenary
        },
        pacmanBottom: {
          position: "absolute",
          content: " ",
          width: "20px",
          height: "10px",
          borderBottomLeftRadius: "10px",
          borderBottomRightRadius: "10px",
          background: colors.quartenary,
          top: "10px"
        },
        point: {
          position: "absolute",
          float: "left",
          background: "transparent",
          width: "10px",
          height: "10px",
          borderWidth: 2,
          borderStyle: "solid",
          borderColor: colors.quartenary,
          borderRadius: "50%",
          transition: "all 0.01s ease-out 0.4s"
        }
      },
      bar: {
        container: {
          position: "absolute",
          height: "10px",
          width: "100%",
          bottom: 0,
          left: 0,
          transition: "all 1s ease-in-out 0.2s",
          zIndex: 1000
        },
        bar: {
          height: "100%",
          background: colors.quartenary,
          transition: "all 0.3s ease-out"
        }
      },
      number: {
        container: {
          position: "absolute",
          bottom: 10,
          right: 10,
          zIndex: 1000,
          color: colors.quartenary
        }
      }
    },
    components: {
      blockquote: {
        textAlign: "left",
        position: "relative",
        display: "inline-block",
        margin: 0
      },
      quote: {
        borderLeft: `1px solid ${colors.primary}`,
        paddingLeft: 40,
        display: "block",
        color: colors.primary,
        fontSize: "4.9rem",
        lineHeight: 1,
        fontWeight: "bold"
      },
      cite: {
        color: colors.tertiary,
        display: "block",
        clear: "left",
        fontSize: "2rem",
        marginTop: 0
      },
      content: {
        margin: "0 auto",
        textAlign: "center"
      },
      codePane: {
        pre: {
          margin: "auto",
          fontSize: "0.8rem",
          fontWeight: "normal",
          fontFamily: fonts.tertiary,
          minWidth: "100%",
          maxWidth: 800
        },
        code: {
          textAlign: "left",
          fontWeight: "normal"
        }
      },
      code: {
        color: "black",
        fontSize: "2.66rem",
        fontFamily: fonts.tertiary,
        margin: 0,
        backgroundColor: "rgba(0,0,0,0.15)",
        padding: "0 10px",
        borderRadius: 3
      },
      heading: {
        h1: {
          color: colors.tertiary,
          fontSize: "7.05rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0,
          zoom: 1
        },
        h2: {
          color: colors.secondary,
          fontSize: "5.88rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h3: {
          color: "black",
          fontSize: "4.9rem",
          fontFamily: fonts.secondary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h4: {
          color: "black",
          fontSize: "3.82rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h5: {
          color: "black",
          fontSize: "3.19rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        },
        h6: {
          color: "black",
          fontSize: "2.66rem",
          fontFamily: fonts.primary,
          lineHeight: 1,
          fontWeight: "bold",
          margin: 0
        }
      },
      image: {
        display: "block",
        margin: 0
      },
      link: {
        textDecoration: "none"
      },
      listItem: {
        fontSize: "2.66rem"
      },
      list: {
        textAlign: "left",
        listStylePosition: "inside",
        padding: 0
      },
      s: {
        strikethrough: {}
      },
      tableHeaderItem: {
        fontSize: "2.66rem",
        fontWeight: "bold"
      },
      tableItem: {
        fontSize: "2.66rem"
      },
      table: {
        width: "100%"
      },
      text: {
        color: "black",
        fontSize: "2.66rem",
        fontFamily: fonts.primary,
        margin: 0
      }
    }
  };
};

export default screen;
<|endoftext|>


<commit_before>/*
 * Flocking Playground
 *   Copyright 2014, Colin Clark
 *
 * Dual licensed under the MIT and GPL Version 2 licenses.
 */

/*global require, window*/

var fluid = fluid || require("infusion"),
    flock = fluid.registerNamespace("flock");

(function () {
    "use strict";

    var $ = fluid.registerNamespace("jQuery");

    // TODO: Declarativize.
    flock.init();

    /**************
     * Playground *
     **************/

    fluid.defaults("flock.playground", {
        gradeNames: ["fluid.viewRelayComponent", "autoInit"],

        flockingSettings: {},

        defaultComponentType: "flock.band",

        model: {
            activeSynthSpec: {},
            isDeclarative: false
        },

        components: {
            enviro: "{environment}",

            demos: {
                type: "flock.playground.demos"
            },

            editor: {
                type: "flock.ui.codeMirror",
                container: "{that}.dom.editor",
                options: {
                    listeners: {
                        onValidChange: "{playground}.events.onSourceUpdated.fire()"
                    }
                }
            },

            demoSelector: {
                type: "flock.playground.demoSelector",
                container: "{that}.dom.demoSelector",
                options: {
                    listeners: {
                        afterDemoLoaded: [
                            {
                                func: "{editor}.setContent",
                                args: ["{arguments}.0"]
                            }

                        ],

                        onSelect: [
                            {
                                func: "{playButton}.pause"
                            }
                        ]
                    }
                }
            },

            playButton: {
                type: "flock.ui.enviroPlayButton",
                container: "{that}.dom.playButton",
                options: {
                    listeners: {
                        onPause: [
                            "{playground}.clearPlayableComponent()",
                            "{enviro}.reset"
                        ]
                    }
                }
            }
        },

        invokers: {
            makePlayableComponent: {
                funcName: "flock.playground.makePlayableComponent",
                args: [
                    "{that}",
                    "{arguments}.0", // A component definition.
                    "{that}.options.defaultComponentType"
                ]
            },

            clearPlayableComponent: {
                funcName: "flock.playground.clearPlayableComponent",
                args: ["{that}"]
            },

            detectSourceType: {
                funcName: "flock.playground.detectSourceType",
                args: ["{editor}", "{that}.applier"],
                dynamic: true
            },

            evaluateSource: {
                funcName: "flock.playground.evaluateSource",
                args: ["{arguments}.0", "{editor}", "{that}.applier"]
            }
        },

        events: {
            onEvaluateDemo: "{playButton}.events.onPlay",
            onSourceUpdated: null
        },

        listeners: {
            onCreate: [
                {
                    funcName: "{demoSelector}.loadDemoFromURL"
                }
            ],

            onEvaluateDemo: [
                {
                    func: "{that}.detectSourceType"
                },
                {
                    func: "{that}.evaluateSource",
                    args: "{that}.model.isDeclarative"
                },
                {
                    func: "{that}.makePlayableComponent",
                    args: ["{that}.model.componentDef"]
                }
            ],

            onSourceUpdated: [
                {
                    func: "{playground}.detectSourceType"
                },
                {
                    func: "{playground}.evaluateSource",
                    args: "{playground}.model.isDeclarative"
                }
            ]
        },

        selectors: {
            editor: "#source-view",
            playButton: "#playButton",
            demoSelector: "#demos"
        }
    });

    // TODO: Better JSON detection.
    // CodeMirror's JavaScript and JSON modes are the same,
    // so we have to detect declarative synths by brute force.
    flock.playground.detectSourceType = function (editor, applier) {
        if (!editor.editor || !editor.editor.getDoc()) {
            return;
        }

        var source = editor.getContent();

        if (source.length < 1) {
            return;
        }

        var trimmed = source.trim(),
            first = trimmed[0],
            last = trimmed[trimmed.length - 1],
            isJSON = (first === "[" && last === "]") || (first === "{" && last === "}");

        applier.change("isDeclarative", isJSON);
    };

    flock.playground.evaluateSource = function (isJSON, editor, applier) {
        if (!editor.editor || !editor.editor.getDoc()) {
            return;
        }

        var source = editor.getContent(),
            fn = isJSON ? flock.playground.parseJSON : flock.playground.evaluateCode;

        fn(source, applier);
    };

    flock.playground.parseJSON = function (source, applier) {
        var componentDef = JSON.parse(source),
            synthSpec = flock.playground.findFirstSynthSpec(componentDef);

        applier.change("componentDef", null);
        applier.change("componentDef", componentDef);

        applier.change("activeSynthSpec", null);
        applier.change("activeSynthSpec", synthSpec);
    };

    flock.playground.matchSynthSpec = function (o) {
        return o && o.synthDef ? o : undefined;
    };

    flock.playground.findInArray = function (arr, fn) {
        var ret,
            match;

        for (var i = 0; i < arr.length; i++) {
            ret = fn(arr[i], i);
            if (ret) {
                return ret;
            } else {
                match = flock.playground.findRecursive(arr[i], fn);
                if (match) {
                    return match;
                }
            }
        }
    };

    flock.playground.findInObject = function (o, fn) {
        var ret,
            match;

        for (var key in o) {
            ret = fn(o[key], key);
            if (ret) {
                return ret;
            } else {
                match = flock.playground.findRecursive(o[key], fn);
                if (match) {
                    return match;
                }
            }
        }
    };

    flock.playground.findRecursive = function (o, fn) {
        if (fluid.isPrimitive(o)) {
            return fn(o);
        }

        var findFn = flock.isIterable(o) ? flock.playground.findInArray :
            flock.playground.findInObject;

        return findFn(o, fn);
    };

    flock.playground.findFirstSynthSpec = function (componentDef) {
        return flock.playground.matchSynthSpec(componentDef) ? componentDef :
            flock.playground.findRecursive(componentDef, flock.playground.matchSynthSpec);
    };

    flock.playground.evaluateCode = function (source) {
        eval(source); // jshint ignore: line
    };

    flock.playground.makePlayableComponent = function (that, componentDef, defaultType) {
        if (!componentDef || !that.model.isDeclarative) {
            return;
        }

        var type = componentDef.synthDef ? "flock.synth" : componentDef.type || defaultType,
            options = componentDef.options || componentDef;

        flock.playground.clearPlayableComponent(that);

        if (options) {
            that.playable = fluid.invokeGlobalFunction(type, [options]);
        }

        return that.playable;
    };

    flock.playground.clearPlayableComponent = function (that) {
        var current = that.playable;
        if (current) {
            current.destroy();
            that.playable = undefined;
        }
    };

    /*****************
     * Demo Selector *
     *****************/

    fluid.defaults("flock.playground.demoSelector", {
        gradeNames: ["fluid.viewComponent", "autoInit"],

        components: {
            selectBox: {
                type: "flock.ui.selectBox",
                container: "{that}.container",
                options: {
                    model: "{demos}.model"
                }
            }
        },

        demoDefaults: {
            pathPrefix: "../demos/",
            id: "sine",
            fileExt: "json"
        },

        invokers: {
            loadDemo: {
                funcName: "flock.playground.demoSelector.load",
                args: [
                    "{arguments}.0",
                    "{that}.options.demoDefaults",
                    "{that}.events.afterDemoLoaded.fire"
                ]
            },

            loadDemoFromURL: {
                funcName: "flock.playground.demoSelector.loadDemoFromURLHash",
                args: ["{that}.container", "{selectBox}", "{that}.loadDemo"]
            },

            updateURL: {
                funcName: "flock.playground.demoSelector.updateURLHash",
                args: ["{arguments}.0.id"]
            }
        },

        events: {
            onSelect: "{selectBox}.events.onSelect",    // Fires when the user selects a demo.
            afterDemoLoaded: null                       // Fires after a demo file has been loaded.
        },

        listeners: {
            onSelect: [
                {
                    funcName: "{that}.updateURL",
                    args: ["{arguments}.0"]
                },
                {
                    funcName: "{that}.loadDemo",
                    args: ["{arguments}.0"]
                }
            ]
        }
    });

    flock.playground.demoSelector.updateURLHash = function (id) {
        if (id) {
            window.location.hash = "#" + id;
        }
    };

    flock.playground.demoSelector.loadDemoFromURLHash = function (container, selectBox) {
        var hash = window.location.hash,
            id = hash ? hash.slice(1) : selectBox.model.defaultOption;

        selectBox.select(id);
    };

    flock.playground.demoSelector.load = function (demo, demoDefaults, afterDemoLoaded) {
        demo = demo || {
            id: demoDefaults.id
        };

        var fileExt = demo.fileExt || demoDefaults.fileExt,
            url = demo.url || (demoDefaults.pathPrefix + demo.id + "." + fileExt);

        $.ajax({
            type: "get",
            url: url,
            dataType: "text",
            success: afterDemoLoaded,
            error: function (xhr, textStatus, errorThrown) {
                throw new Error(textStatus + " while loading " + url + ": " + errorThrown);
            }
        });
    };

}());
<commit_msg>Fixes bug where demos wouldn't load when URL hash changed.<commit_after>/*
 * Flocking Playground
 *   Copyright 2014, Colin Clark
 *
 * Dual licensed under the MIT and GPL Version 2 licenses.
 */

/*global require, window*/

var fluid = fluid || require("infusion"),
    flock = fluid.registerNamespace("flock");

(function () {
    "use strict";

    var $ = fluid.registerNamespace("jQuery");

    // TODO: Declarativize.
    flock.init();

    /**************
     * Playground *
     **************/

    fluid.defaults("flock.playground", {
        gradeNames: ["fluid.viewRelayComponent", "autoInit"],

        flockingSettings: {},

        defaultComponentType: "flock.band",

        model: {
            activeSynthSpec: {},
            isDeclarative: false
        },

        components: {
            enviro: "{environment}",

            demos: {
                type: "flock.playground.demos"
            },

            editor: {
                type: "flock.ui.codeMirror",
                container: "{that}.dom.editor",
                options: {
                    listeners: {
                        onValidChange: "{playground}.events.onSourceUpdated.fire()"
                    }
                }
            },

            demoSelector: {
                type: "flock.playground.demoSelector",
                container: "{that}.dom.demoSelector",
                options: {
                    listeners: {
                        afterDemoLoaded: [
                            {
                                func: "{editor}.setContent",
                                args: ["{arguments}.0"]
                            }

                        ],

                        onSelect: [
                            {
                                func: "{playButton}.pause"
                            }
                        ]
                    }
                }
            },

            playButton: {
                type: "flock.ui.enviroPlayButton",
                container: "{that}.dom.playButton",
                options: {
                    listeners: {
                        onPause: [
                            "{playground}.clearPlayableComponent()",
                            "{enviro}.reset"
                        ]
                    }
                }
            }
        },

        invokers: {
            makePlayableComponent: {
                funcName: "flock.playground.makePlayableComponent",
                args: [
                    "{that}",
                    "{arguments}.0", // A component definition.
                    "{that}.options.defaultComponentType"
                ]
            },

            clearPlayableComponent: {
                funcName: "flock.playground.clearPlayableComponent",
                args: ["{that}"]
            },

            detectSourceType: {
                funcName: "flock.playground.detectSourceType",
                args: ["{editor}", "{that}.applier"],
                dynamic: true
            },

            evaluateSource: {
                funcName: "flock.playground.evaluateSource",
                args: ["{arguments}.0", "{editor}", "{that}.applier"]
            }
        },

        events: {
            onEvaluateDemo: "{playButton}.events.onPlay",
            onSourceUpdated: null
        },

        listeners: {
            onCreate: [
                {
                    funcName: "{demoSelector}.loadDemoFromURL"
                }
            ],

            onEvaluateDemo: [
                {
                    func: "{that}.detectSourceType"
                },
                {
                    func: "{that}.evaluateSource",
                    args: "{that}.model.isDeclarative"
                },
                {
                    func: "{that}.makePlayableComponent",
                    args: ["{that}.model.componentDef"]
                }
            ],

            onSourceUpdated: [
                {
                    func: "{playground}.detectSourceType"
                },
                {
                    func: "{playground}.evaluateSource",
                    args: "{playground}.model.isDeclarative"
                }
            ]
        },

        selectors: {
            editor: "#source-view",
            playButton: "#playButton",
            demoSelector: "#demos"
        }
    });

    // TODO: Better JSON detection.
    // CodeMirror's JavaScript and JSON modes are the same,
    // so we have to detect declarative synths by brute force.
    flock.playground.detectSourceType = function (editor, applier) {
        if (!editor.editor || !editor.editor.getDoc()) {
            return;
        }

        var source = editor.getContent();

        if (source.length < 1) {
            return;
        }

        var trimmed = source.trim(),
            first = trimmed[0],
            last = trimmed[trimmed.length - 1],
            isJSON = (first === "[" && last === "]") || (first === "{" && last === "}");

        applier.change("isDeclarative", isJSON);
    };

    flock.playground.evaluateSource = function (isJSON, editor, applier) {
        if (!editor.editor || !editor.editor.getDoc()) {
            return;
        }

        var source = editor.getContent(),
            fn = isJSON ? flock.playground.parseJSON : flock.playground.evaluateCode;

        fn(source, applier);
    };

    flock.playground.parseJSON = function (source, applier) {
        var componentDef = JSON.parse(source),
            synthSpec = flock.playground.findFirstSynthSpec(componentDef);

        applier.change("componentDef", null);
        applier.change("componentDef", componentDef);

        applier.change("activeSynthSpec", null);
        applier.change("activeSynthSpec", synthSpec);
    };

    flock.playground.matchSynthSpec = function (o) {
        return o && o.synthDef ? o : undefined;
    };

    flock.playground.findInArray = function (arr, fn) {
        var ret,
            match;

        for (var i = 0; i < arr.length; i++) {
            ret = fn(arr[i], i);
            if (ret) {
                return ret;
            } else {
                match = flock.playground.findRecursive(arr[i], fn);
                if (match) {
                    return match;
                }
            }
        }
    };

    flock.playground.findInObject = function (o, fn) {
        var ret,
            match;

        for (var key in o) {
            ret = fn(o[key], key);
            if (ret) {
                return ret;
            } else {
                match = flock.playground.findRecursive(o[key], fn);
                if (match) {
                    return match;
                }
            }
        }
    };

    flock.playground.findRecursive = function (o, fn) {
        if (fluid.isPrimitive(o)) {
            return fn(o);
        }

        var findFn = flock.isIterable(o) ? flock.playground.findInArray :
            flock.playground.findInObject;

        return findFn(o, fn);
    };

    flock.playground.findFirstSynthSpec = function (componentDef) {
        return flock.playground.matchSynthSpec(componentDef) ? componentDef :
            flock.playground.findRecursive(componentDef, flock.playground.matchSynthSpec);
    };

    flock.playground.evaluateCode = function (source) {
        eval(source); // jshint ignore: line
    };

    flock.playground.makePlayableComponent = function (that, componentDef, defaultType) {
        if (!componentDef || !that.model.isDeclarative) {
            return;
        }

        var type = componentDef.synthDef ? "flock.synth" : componentDef.type || defaultType,
            options = componentDef.options || componentDef;

        flock.playground.clearPlayableComponent(that);

        if (options) {
            that.playable = fluid.invokeGlobalFunction(type, [options]);
        }

        return that.playable;
    };

    flock.playground.clearPlayableComponent = function (that) {
        var current = that.playable;
        if (current) {
            current.destroy();
            that.playable = undefined;
        }
    };

    /*****************
     * Demo Selector *
     *****************/

    fluid.defaults("flock.playground.demoSelector", {
        gradeNames: ["fluid.viewComponent", "autoInit"],

        components: {
            selectBox: {
                type: "flock.ui.selectBox",
                container: "{that}.container",
                options: {
                    model: "{demos}.model"
                }
            }
        },

        demoDefaults: {
            pathPrefix: "../demos/",
            id: "sine",
            fileExt: "json"
        },

        invokers: {
            loadDemo: {
                funcName: "flock.playground.demoSelector.load",
                args: [
                    "{arguments}.0",
                    "{that}.options.demoDefaults",
                    "{that}.events.afterDemoLoaded.fire"
                ]
            },

            loadDemoFromURL: {
                funcName: "flock.playground.demoSelector.loadDemoFromURLHash",
                args: ["{that}.container", "{selectBox}", "{that}.loadDemo"]
            },

            updateURL: {
                funcName: "flock.playground.demoSelector.updateURLHash",
                args: ["{arguments}.0.id"]
            }
        },

        events: {
            onSelect: "{selectBox}.events.onSelect",    // Fires when the user selects a demo.
            onURLHashChange: null,
            afterDemoLoaded: null                       // Fires after a demo file has been loaded.
        },

        listeners: {
            onCreate: {
                funcName: "flock.playground.demoSelector.listenForHashChanges",
                args: ["{that}.events.onURLHashChange.fire"]
            },

            onURLHashChange: {
                func: "{that}.loadDemoFromURL"
            },

            onSelect: [
                {
                    funcName: "{that}.updateURL",
                    args: ["{arguments}.0"]
                },
                {
                    funcName: "{that}.loadDemo",
                    args: ["{arguments}.0"]
                }
            ]
        }
    });

    flock.playground.demoSelector.listenForHashChanges = function (onURLHashChange) {
        $(window).bind("hashchange", onURLHashChange);
    };

    flock.playground.demoSelector.updateURLHash = function (id) {
        if (id) {
            window.location.hash = "#" + id;
        }
    };

    flock.playground.demoSelector.loadDemoFromURLHash = function (container, selectBox) {
        var hash = window.location.hash,
            id = hash ? hash.slice(1) : selectBox.model.defaultOption;

        selectBox.select(id);
    };

    flock.playground.demoSelector.load = function (demo, demoDefaults, afterDemoLoaded) {
        demo = demo || {
            id: demoDefaults.id
        };

        var fileExt = demo.fileExt || demoDefaults.fileExt,
            url = demo.url || (demoDefaults.pathPrefix + demo.id + "." + fileExt);

        $.ajax({
            type: "get",
            url: url,
            dataType: "text",
            success: afterDemoLoaded,
            error: function (xhr, textStatus, errorThrown) {
                throw new Error(textStatus + " while loading " + url + ": " + errorThrown);
            }
        });
    };

}());
<|endoftext|>


<commit_before>// component-requires.js is a generated file in rsg.js that contains
// the list of required user-defined components
import Components from '../../rcs-tmp/component-requires'
import reactPropMeta from '../../rcs-tmp/propsdoc'

// for `commonStrict` module formatter
// https://babeljs.io/docs/usage/modules/#interop
let Contents = Components
  .map((Content) => Content.default || Content)
//  .filter((Component) => Component.styleguide)
//// compare index numbers
//  .sort((a, b) => {
//    a = a.styleguide.index
//    b = b.styleguide.index
//
//    return !a ? 1 : !b ? -1 : a.toString().localeCompare(b)
//  })
  //create example readme if not included for ecology live demo
  .map((Component) => {
    if (reactPropMeta[Component.name]) {
        var description;
        var code;

        Component.styleguide = Component.styleguide || {};

        if ( !Component.styleguide.title ) {
            Component.styleguide.title = Component.name;
        }

        if ( !Component.styleguide.description ) {
            description = reactPropMeta[Component.name].description;
        } else if (Component.styleguide.description) {
            description = Component.styleguide.description;
        }

        if ( !Component.styleguide.example ) {
            code = '\n<' + Component.name + '></' + Component.name + '>\n';
        } else if (Component.styleguide.example) {
            code = Component.styleguide.example;
        }

        Component.styleguide.readme =   '# ' + Component.styleguide.title + '\n' +
                                        description + '\n' +
                                        '```playground\n' +
                                        code +
                                        '```\n' +
                                        '### Properties';
         return Component
    } else {
        return Component
    }
  });

export default {
  /**
   * @type {string[]}
   */
  navList: (() => {
    const components = {}

    const categories = Contents
      .map((Content) => {
        const styleguide = Content.styleguide;
        styleguide.category = styleguide.category ? styleguide.category : 'Misc. Component List';
        components[styleguide.category] = components[styleguide.category] ? components[styleguide.category] : [];
        components[styleguide.category].push(styleguide.title);

        return Content.styleguide.category
      })
      .filter((category, i, categories) => categories.indexOf(category) === i);

    return {
      categories: categories,
      components: components
    }
  })(),

  /**
   * @param {Object=} data
   * @param {string=} data.query
   * @param {string[]=} data.keys
   * @param {boolean=} data.exact
   * @returns {ReactClass[]}
   */
  search (data) {
    data = data || {}

    let query = (data.query || '').trim().toLowerCase()
    let keys = data.keys || []
    let exact = !!data.exact
    let phrases = !exact ? query.split(' ') : null

    if (query === '') {
      return Contents
    }

    return Contents.filter((Content) => {
      return keys
        .filter((key) => !!Content.styleguide[key])
        .some((key) => {
          let val = Content.styleguide[key].toLowerCase()

          return exact ? val === query : phrases.every((phrase) => val.indexOf(phrase) !== -1)
        })
    })
  }
}
<commit_msg>more robust default component example<commit_after>// component-requires.js is a generated file in rsg.js that contains
// the list of required user-defined components
import Components from '../../rcs-tmp/component-requires'
import reactPropMeta from '../../rcs-tmp/propsdoc'

// for `commonStrict` module formatter
// https://babeljs.io/docs/usage/modules/#interop
let Contents = Components
  .map((Content) => Content.default || Content)
//  .filter((Component) => Component.styleguide)
//// compare index numbers
//  .sort((a, b) => {
//    a = a.styleguide.index
//    b = b.styleguide.index
//
//    return !a ? 1 : !b ? -1 : a.toString().localeCompare(b)
//  })
  //create example readme if not included for ecology live demo
  .map((Component) => {
    if (reactPropMeta[Component.name]) {
        var description;
        var code;

        Component.styleguide = Component.styleguide || {};

        if ( !Component.styleguide.title ) {
            Component.styleguide.title = Component.name;
        }

        if ( !Component.styleguide.description ) {
            description = reactPropMeta[Component.name].description;
        } else if (Component.styleguide.description) {
            description = Component.styleguide.description;
        }

        if ( !Component.styleguide.example ) {
            var propString = '';
            var childrenString = '';
            for (var key in reactPropMeta[Component.name].props) {
                if (key != "children" && reactPropMeta[Component.name].props[key].required && reactPropMeta[Component.name].props[key].defaultValue){
                    propString += ` ${key}=${reactPropMeta[Component.name].props[key].defaultValue.value}`
                } else if (key == "children" && reactPropMeta[Component.name].props[key].defaultValue) {

                    if (reactPropMeta[Component.name].props[key].defaultValue.value.substr(0, 1) === "'" && reactPropMeta[Component.name].props[key].defaultValue.value.substr(-1) === "'"){
                        childrenString = '\n    '+reactPropMeta[Component.name].props[key].defaultValue.value.slice(1, -1)+'\n';
                    } else {
                        childrenString = '\n    '+reactPropMeta[Component.name].props[key].defaultValue.value+'\n';
                    }
                }
            }

            code = '\n<' + Component.name + propString+'>'+childrenString+'</' + Component.name + '>\n';
        } else if (Component.styleguide.example) {
            code = Component.styleguide.example;
        }

        Component.styleguide.readme =   '# ' + Component.styleguide.title + '\n' +
                                        description + '\n' +
                                        '```playground\n' +
                                        code +
                                        '```\n' +
                                        '### Properties';
         return Component
    } else {
        return Component
    }
  });

export default {
  /**
   * @type {string[]}
   */
  navList: (() => {
    const components = {}

    const categories = Contents
      .map((Content) => {
        const styleguide = Content.styleguide;
        styleguide.category = styleguide.category ? styleguide.category : 'Misc. Component List';
        components[styleguide.category] = components[styleguide.category] ? components[styleguide.category] : [];
        components[styleguide.category].push(styleguide.title);

        return Content.styleguide.category
      })
      .filter((category, i, categories) => categories.indexOf(category) === i);

    return {
      categories: categories,
      components: components
    }
  })(),

  /**
   * @param {Object=} data
   * @param {string=} data.query
   * @param {string[]=} data.keys
   * @param {boolean=} data.exact
   * @returns {ReactClass[]}
   */
  search (data) {
    data = data || {}

    let query = (data.query || '').trim().toLowerCase()
    let keys = data.keys || []
    let exact = !!data.exact
    let phrases = !exact ? query.split(' ') : null

    if (query === '') {
      return Contents
    }

    return Contents.filter((Content) => {
      return keys
        .filter((key) => !!Content.styleguide[key])
        .some((key) => {
          let val = Content.styleguide[key].toLowerCase()

          return exact ? val === query : phrases.every((phrase) => val.indexOf(phrase) !== -1)
        })
    })
  }
}
<|endoftext|>