<commit_before>// ==UserScript==
// @name         RohBot Currency Converter
// @version      1.21
// @description  Allows the user to select their currency and then converts any found currencies to the one the user selected
// @author       Spans
// @match        https://rohbot.net
// @grant        none
// @updateURL	 https://raw.githubusercontent.com/Spanfile/RohBot-Currency-Converter/master/converter.js
// @require		 http://openexchangerates.github.io/money.js/money.min.js
// ==/UserScript==

var cacheKey = "spans-currency-cache";
var storeKey = "spans-currency";
var enabled = false;
var user = "eur";

var currencies = {
	usd: { name: "USD", symbol: "$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)\$(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?)\$(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?)(?: dollars?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) penn(?:y|ies)(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.01 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) nickels?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.05 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) dimes?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.1 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) quarters?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.25 }
	]},
	eur: { name: "EUR", symbol: "€", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?)(?:€|e| eur(?:o|os)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)€(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }
	]},
	gbp: { name: "GBP", symbol: "£", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?)£(?=\s|$|,|\.|!|\?|\*)/ig }, // the £ is for £
		{ regex: /(?:\s|^|,|\.|!|\?|\*)£(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?)(?:p| pence)(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.01}
	]},
	cad: { name: "CAD", symbol: "CA$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)CA\$(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	aud: { name: "AUD", symbol: "A$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)A\$(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	nzd: { name: "NZD", symbol: "NZ$", pos :"pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)NZ\$(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	sek: { name: "SEK", symbol: " kr", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) ?kr(?=\s|$|,|\.|!|\?|\*)/ig }]}, // kr defaults to swedish kronor
	nok: { name: "NOK", symbol: " nok", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) ?nok(?=\s|$|,|\.|!|\?|\*)/ig }]}, // special cases for norwegian and danish kronor whatevers
	dkk: { name: "DKK", symbol: " dkk", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)(\d+(?:(?:\.|,)\d+)?) ?dkk(?=\s|$|,|\.|!|\?|\*)/ig }]},
	zar: { name: "ZAR", symbol: "R", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)R(\d+(?:(?:\.|,)\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]}
};

// first of all, setup the currency conversion
var cached = RohStore.get(cacheKey);
if (cached) {
	var cachedObj = JSON.parse(cached);
	fx.base = cachedObj.base;
	fx.rates = cachedObj.rates;
	enabled = true;
}

$.getJSON("https://api.fixer.io/latest", function(data) {
	if (typeof fx !== "undefined" && fx.rates) {
		fx.base = data.base;
		fx.rates = data.rates;
		enabled = true;
		cacheRates();
	}

	//console.log("Currency test: €1 = $" + fx(1).from("EUR").to("USD"));
});

function cacheRates() {
	RohStore.set(cacheKey, JSON.stringify({
		base: fx.base,
		rates: fx.rates
	}));
}

function load() {
	user = RohStore.get(storeKey) || "eur"; // haha fuck you americans
}

function save() {
	RohStore.set(storeKey, user);
}

chatMgr.lineFilter.add(function(line, prepend, e) {
	if (!enabled)
		return;

	line.Content = applyConversions(line.Content);
});

cmd.register("currency", "-", function(chat, args) {
	if (args.length != 1 || args[0].length === 0 || !currencies.hasOwnProperty(args[0])) {
		chat.statusMessage("Usage: /currency (" + Object.keys(currencies).join("|") + ")");
	}

	user = args[0];
	chat.statusMessage("Your preferred currency has been set to " + currencies[user].name);
	save();
});

function applyConversions(message) {
	var results = [];
	var userCurrency = currencies[user.toLowerCase()]; // toLowerCase() in case it's in upper case

	// try to find and convert any currencies except the users currency found in the message to the users currency
	for (var key in currencies) {
		if (currencies.hasOwnProperty(key)) { // hasOwnProperty() makes sure we don't loop over stuff inherited from the object's prototype
			var currency = currencies[key];

			if (currency.name != userCurrency.name) {
				var result = commonConversion(message, currency, userCurrency);

				if (result.length > 0) {
					results.push(result);
				}
			}
		}
	}

	// since the converters can return multiple conversions, flatten the results
	// the result looks like [[{stuff here}, {stuff here}], [{stuff here}, {stuff here}]]
	// flattening it turns it into [{stuff here}, {stuff here}, {stuff here}, {stuff here}]
	var flattened = [].concat.apply([], results);

	// sort them
	flattened.sort(function(a, b) {
		if (a.index > b.index) {
			return 1;
		}

		if (a.index < b.index) {
			return -1;
		}

		return 0;
	});

	var newMsg = message;
	var inserted = 0;
	// combine them all
	flattened.forEach(function(result) {
		var title = formatCurrency(result.conversion, result.currency);
		var original = result.original;
		var begin = "";

		// because the js regex engine doesn't support positive lookbehinds, the regexes return the whitespace before every match
		// most of the time they do it unless the match is at the start of the message
		// in case there is a whitespace, remove it and have one added before the  tag
		if (original.substring(0, 1) == " ") {
			original = original.substring(1);
			begin = " ";
		}

		var toInsert = begin + "" + original + "";
		newMsg = newMsg.splice(result.index + inserted, result.original.length, toInsert);
		inserted += toInsert.length - result.original.length;
	});

	return newMsg;
}

function commonConversion(message, from, to) {
	var m;
	var results = [];

	from.regexes.forEach(function(regexModifierPair) {
		while ((m = regexModifierPair.regex.exec(message)) !== null) {
			if (m.index === regexModifierPair.regex.lastIndex) {
				regex.lastIndex++;
			}

			var amount = Number(m[1].replace(',', '.')) * (regexModifierPair.modifier || 1); // js wants dots as decimal separators
			var converted = Math.round(fx(amount).from(from.name).to(to.name) * 100) / 100; // two decimals is enough for currencies

			results[results.length] = {original: m[0], index: m.index, conversion: converted, currency: to};
		}
	});

	return results;
}

function formatCurrency(value, currency) {
	return currency.pos === "pre" ? currency.symbol + value : value + currency.symbol;
}

String.prototype.splice = function(idx, rem, s) {
	return (this.slice(0, idx) + s + this.slice(idx + Math.abs(rem)));
};

load();
<commit_msg>Regexes handle thousand separator commas properly<commit_after>// ==UserScript==
// @name         RohBot Currency Converter
// @version      1.22
// @description  Allows the user to select their currency and then converts any found currencies to the one the user selected
// @author       Spans
// @match        https://rohbot.net
// @grant        none
// @updateURL	 https://raw.githubusercontent.com/Spanfile/RohBot-Currency-Converter/master/converter.js
// @require		 http://openexchangerates.github.io/money.js/money.min.js
// ==/UserScript==

var cacheKey = "spans-currency-cache";
var storeKey = "spans-currency";
var enabled = false;
var user = "eur";

var currencies = {
	usd: { name: "USD", symbol: "$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)\$([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?)\$(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?)(?: dollars?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) penn(?:y|ies)(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.01 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) nickels?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.05 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) dimes?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.1 },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) quarters?(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.25 }
	]},
	eur: { name: "EUR", symbol: "€", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?)(?:€|e| eur(?:o|os)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)€([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }
	]},
	gbp: { name: "GBP", symbol: "£", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?)£(?=\s|$|,|\.|!|\?|\*)/ig }, // the £ is for £
		{ regex: /(?:\s|^|,|\.|!|\?|\*)£([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig },
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?)(?:p| pence)(?=\s|$|,|\.|!|\?|\*)/ig, modifier: 0.01}
	]},
	cad: { name: "CAD", symbol: "CA$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)CA\$([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	aud: { name: "AUD", symbol: "A$", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)A\$([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	nzd: { name: "NZD", symbol: "NZ$", pos :"pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)NZ\$([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]},
	sek: { name: "SEK", symbol: " kr", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) ?kr(?=\s|$|,|\.|!|\?|\*)/ig }]}, // kr defaults to swedish kronor
	nok: { name: "NOK", symbol: " nok", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) ?nok(?=\s|$|,|\.|!|\?|\*)/ig }]}, // special cases for norwegian and danish kronor whatevers
	dkk: { name: "DKK", symbol: " dkk", pos: "post", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)([\d,]+(?:\.\d+)?) ?dkk(?=\s|$|,|\.|!|\?|\*)/ig }]},
	zar: { name: "ZAR", symbol: "R", pos: "pre", regexes: [
		{ regex: /(?:\s|^|,|\.|!|\?|\*)R([\d,]+(?:\.\d+)?)(?=\s|$|,|\.|!|\?|\*)/ig }]}
};

// first of all, setup the currency conversion
var cached = RohStore.get(cacheKey);
if (cached) {
	var cachedObj = JSON.parse(cached);
	fx.base = cachedObj.base;
	fx.rates = cachedObj.rates;
	enabled = true;
}

$.getJSON("https://api.fixer.io/latest", function(data) {
	if (typeof fx !== "undefined" && fx.rates) {
		fx.base = data.base;
		fx.rates = data.rates;
		enabled = true;
		cacheRates();
	}

	//console.log("Currency test: €1 = $" + fx(1).from("EUR").to("USD"));
});

function cacheRates() {
	RohStore.set(cacheKey, JSON.stringify({
		base: fx.base,
		rates: fx.rates
	}));
}

function load() {
	user = RohStore.get(storeKey) || "eur"; // haha fuck you americans
}

function save() {
	RohStore.set(storeKey, user);
}

chatMgr.lineFilter.add(function(line, prepend, e) {
	if (!enabled)
		return;

	line.Content = applyConversions(line.Content);
});

cmd.register("currency", "-", function(chat, args) {
	if (args.length != 1 || args[0].length === 0 || !currencies.hasOwnProperty(args[0])) {
		chat.statusMessage("Usage: /currency (" + Object.keys(currencies).join("|") + ")");
	}

	user = args[0];
	chat.statusMessage("Your preferred currency has been set to " + currencies[user].name);
	save();
});

function applyConversions(message) {
	var results = [];
	var userCurrency = currencies[user.toLowerCase()]; // toLowerCase() in case it's in upper case

	// try to find and convert any currencies except the users currency found in the message to the users currency
	for (var key in currencies) {
		if (currencies.hasOwnProperty(key)) { // hasOwnProperty() makes sure we don't loop over stuff inherited from the object's prototype
			var currency = currencies[key];

			if (currency.name != userCurrency.name) {
				var result = commonConversion(message, currency, userCurrency);

				if (result.length > 0) {
					results.push(result);
				}
			}
		}
	}

	// since the converters can return multiple conversions, flatten the results
	// the result looks like [[{stuff here}, {stuff here}], [{stuff here}, {stuff here}]]
	// flattening it turns it into [{stuff here}, {stuff here}, {stuff here}, {stuff here}]
	var flattened = [].concat.apply([], results);

	// sort them
	flattened.sort(function(a, b) {
		if (a.index > b.index) {
			return 1;
		}

		if (a.index < b.index) {
			return -1;
		}

		return 0;
	});

	var newMsg = message;
	var inserted = 0;
	// combine them all
	flattened.forEach(function(result) {
		var title = formatCurrency(result.conversion, result.currency);
		var original = result.original;
		var begin = "";

		// because the js regex engine doesn't support positive lookbehinds, the regexes return the whitespace before every match
		// most of the time they do it unless the match is at the start of the message
		// in case there is a whitespace, remove it and have one added before the  tag
		if (original.substring(0, 1) == " ") {
			original = original.substring(1);
			begin = " ";
		}

		var toInsert = begin + "" + original + "";
		newMsg = newMsg.splice(result.index + inserted, result.original.length, toInsert);
		inserted += toInsert.length - result.original.length;
	});

	return newMsg;
}

function commonConversion(message, from, to) {
	var m;
	var results = [];

	from.regexes.forEach(function(regexModifierPair) {
		while ((m = regexModifierPair.regex.exec(message)) !== null) {
			if (m.index === regexModifierPair.regex.lastIndex) {
				regex.lastIndex++;
			}

			var amount = Number(m[1].replace(',', '.')) * (regexModifierPair.modifier || 1); // js wants dots as decimal separators
			var converted = Math.round(fx(amount).from(from.name).to(to.name) * 100) / 100; // two decimals is enough for currencies

			results[results.length] = {original: m[0], index: m.index, conversion: converted, currency: to};
		}
	});

	return results;
}

function formatCurrency(value, currency) {
	return currency.pos === "pre" ? currency.symbol + value : value + currency.symbol;
}

String.prototype.splice = function(idx, rem, s) {
	return (this.slice(0, idx) + s + this.slice(idx + Math.abs(rem)));
};

load();
<|endoftext|>


<commit_before>var React = require('react/addons');
var Router = require("react-router");
var routes = require('./routes');

module.exports = function(app) {

	app.use(function(req, res, next) {

		// We customize the onAbort method in order to handle redirects
		  var router = Router.create({
		    routes: routes,
		    location: req.path,
		    onAbort: function defaultAbortHandler(abortReason, location) {
		      if (abortReason && abortReason.to) {
		        res.redirect(301, abortReason.to);
		      } else {
		        res.redirect(404, "404");
		      }
		    }
		  });

		// React.renderToString takes your component
	    // and generates the markup

		//var reactHtml = React.renderToString(ReactApp({}));

        var reactHtml = "";
        router.run(function (Handler, state) {
            reactHtml = React.renderToString(React.createElement(Handler, {
                routerState: state,
                //deviceType: deviceType,
                environment: "server"
            }), null);
        });

	    // Output html rendered by react
		// console.log(myAppHtml);
	    res.render('index.ejs', {reactOutput: reactHtml});
	});

};<commit_msg>Made NotFoundRoute return a 404 status<commit_after>var React = require('react/addons');
var Router = require("react-router");
var routes = require('./routes');

module.exports = function(app) {

	app.use(function(req, res, next) {

		// We customize the onAbort method in order to handle redirects
        var router = Router.create({
            routes: routes,
            location: req.path,
            onAbort: function defaultAbortHandler(abortReason, location) {
                if (abortReason && abortReason.to) {
                    res.redirect(301, abortReason.to);
                } else {  // TODO: Is this needed?
                    res.redirect(404, "404");
                }
            }
        });

        router.run(function (Handler, state) {
            var html = React.renderToString(React.createElement(Handler, {
                routerState: state,
                //deviceType: deviceType,
                environment: "server"
            }), null);
            if (state.routes[1].isNotFound) {
                res.status(400);
            }
            res.render('index.ejs', { reactOutput: html} );
        });
	});
};<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const Marked = CompLibrary.Marked; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;
const Prism = CompLibrary.Prism;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (

        <a className={`button ${this.props.className}`} href={this.props.href} target={this.props.target}>
          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self"
};

const code =`let component = ReasonReact.statelessComponent "Greeting";

let make ::name _children => {
  ...component,
  render: fun _self =>
    <button>
      (ReasonReact.stringToElement "Hello!")
    </button>
};`;

class HomeSplash extends React.Component {
  //
  render() {
    let promoSection =

            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/getting-started.html"
              }
            >
              <translate>Get Started</translate>
            </Button>
            <Button
              href="https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial"
            >
              Tutorial
            </Button>

;
    return (

            Hello! This particular page hash has moved to .
            Please update the URLs to reflect it. Thanks!

{siteConfig.title}

{siteConfig.tagline}

                <Prism>{code}</Prism>

            {promoSection}

    );
  }
}

class Index extends React.Component {
  //
            // <GridBlock
            //   contents={[
            //     {
            //       content: "Talk about learning how to use this",
            //       image: siteConfig.baseUrl + "img/logo.png",
            //       title: "Quick Start"
            //     },
            //     {
            //       content: "Talk about learning how to use this",
            //       image: siteConfig.baseUrl + "img/logo.png",
            //       title: "Examples"
            //     },
            //   ]}
            //   layout="twoColumn"
            // />
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (

        );
      });

    return (

        <HomeSplash language={language} />

          <Container className="homeThreePoints" padding={["bottom"]}>
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>
          <Container padding={["bottom"]} className="homeTwoPoints">
          </Container>

    );
  }
}

module.exports = Index;
<commit_msg>[Docs] Sleep<commit_after>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const Marked = CompLibrary.Marked; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;
const Prism = CompLibrary.Prism;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (

        <a className={`button ${this.props.className}`} href={this.props.href} target={this.props.target}>
          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self"
};

const codeExample =`let component = ReasonReact.statelessComponent "Greeting";

let make ::name _children => {
  ...component,
  render: fun _self =>
    <button>
      (ReasonReact.stringToElement "Hello!")
    </button>
};`;

//

const quickStartScript1 = `npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app
npm install && npm start`;

const quickStartScript2 = `npm run build`;

class HomeSplash extends React.Component {
  render() {
    let promoSection =

            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/getting-started.html"
              }
            >
              <translate>Get Started</translate>
            </Button>
            <Button
              href="https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial"
            >
              Tutorial
            </Button>

;

    return (

            Hello! This particular page hash has moved to .
            Please update the URLs to reflect it. Thanks!

{siteConfig.title}

{siteConfig.tagline}

                <Prism>{codeExample}</Prism>

            {promoSection}

    );
  }
}

class Index extends React.Component {
  //
            // <GridBlock
            //   contents={[
            //     {
            //       content: "Talk about learning how to use this",
            //       image: siteConfig.baseUrl + "img/logo.png",
            //       title: "Quick Start"
            //     },
            //     {
            //       content: "Talk about learning how to use this",
            //       image: siteConfig.baseUrl + "img/logo.png",
            //       title: "Examples"
            //     },
            //   ]}
            //   layout="twoColumn"
            // />
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (

        );
      });

    return (

        <HomeSplash language={language} />

          <Container className="homeThreePoints" padding={["bottom"]}>
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>
          <Container padding={["bottom"]} className="homeTwoPoints">

Quick Start

                <Prism>{quickStartScript1}</Prism>

              Then open another tab and do:

                <Prism>{quickStartScript2}</Prism>

              Your apps are in the html files inside `src/`!

Examples

ReasonReact Hacker News

img

TodoMVC

img2

          </Container>

    );
  }
}

module.exports = Index;
<|endoftext|>


<commit_before>/**
 * Created by tsa on 03.08.2016.
 */
<commit_msg>unneccessary file<commit_after><|endoftext|>


<commit_before>exports.setup = function(Tests){

Tests.describe('Planet API: Delete', function(it){

	it('should delete by key (string)', function(expect){
		expect.perform(12);

		var first = io.connect(null, {'force new connection': 1});

		first.on('connect', function(){
			first.emit('put', {
				'key-a': 12,
				'key-b': 'ok',
				'key-c': null,
				'key-d': [],
				'key-e': {},
				'key-f': false
			});
		});

		first.on('put', function(data){

			first.emit('delete', 'key-a');
			first.emit('delete', 'key-b');
			first.emit('delete', 'key-c');
			first.emit('delete', 'key-d');
			first.emit('delete', 'key-e');
			first.emit('delete', 'key-f');

			this.disconnect();
		});

		first.on('delete', function(key){
			expect(key).toMatch(/key-[a-f]/);
		});

		first.on('disconnect', function(data){

			var second = io.connect(null, {'force new connection': 1});

			second.on('get', function(data){
				expect(data).toBeType('object');
				expect(data).not.toHaveProperty('key-a');
				expect(data).not.toHaveProperty('key-b');
				expect(data['key-c']).not.toBeNull();
				expect(data).not.toHaveProperty('key-d');
				expect(data['key-e']).not.toBeType('object');
				expect(data['key-f']).not.toBeType('boolean');
				this.disconnect();
			});
		});
	});

	it('should delete a nested object by path (array)', function(expect){
		expect.perform(10);

		var first = io.connect(null, {'force new connection': 1});

		first.on('connect', function(){
			first.emit('put', {
				'veggies': null,
				'fruits': {
					'apples': 2,
					'oranges': 3
				}
			});
		});

		first.on('put', function(data){
			first.emit('delete', ['fruits', 'apples']);
		});

		first.on('delete', function(key){
			expect(key).toBeType('array');
			expect(key[0]).toBe('fruits');
			expect(key[1]).toBe('apples');
			this.disconnect();
		});

		first.on('disconnect', function(data){

			var second = io.connect(null, {'force new connection': 1});

			second.on('get', function(data){
				expect(data).toBeType('object');
				expect(data).toHaveProperty('veggies');
				expect(data).toHaveProperty('fruits');
				expect(data['fruits']).toBeType('object');
				expect('apples' in data['fruits']).toBeFalse();
				expect(data['fruits']).toHaveProperty('oranges');
				expect(data['fruits']['oranges']).toBe(3);
				this.disconnect();
			});
		});

		// TODO: delete null
	});

});

};
<commit_msg>test deleting properties with different types<commit_after>exports.setup = function(Tests){

var Spy = require('../testigo/Source/lib/spy').Spy;

Tests.describe('Planet API: Delete', function(it){

	it('should delete by key (string)', function(expect){
		expect.perform(17);
		var spy = new Spy();

		var first = io.connect(null, {'force new connection': 1});

		first.on('connect', function(){
			first.emit('put', {
				'key-a': 12,
				'key-b': 'ok',
				'key-c': null,
				'key-d': [],
				'key-e': {},
				'key-f': false
			});
		});

		first.on('put', function(data){
			first.emit('delete', 'key-a');
			first.emit('delete', 'key-b');
			first.emit('delete', 'key-c');
			first.emit('delete', 'key-d');
			first.emit('delete', 'key-e');
			first.emit('delete', 'key-f');
			this.disconnect();
		});

		first.on('delete', function(key){
			spy();
			expect(key).toMatch(/key-[a-f]/);
		});

		first.on('disconnect', function(data){

			var second = io.connect(null, {'force new connection': 1});

			second.on('get', function(data){
				expect(spy.getCallCount()).toBe(6);
				expect(data).toBeType('object');
				expect(data).not.toHaveProperty('key-a');
				expect(data).not.toHaveProperty('key-b');
				expect(data).not.toHaveProperty('key-c');
				expect(data['key-c']).not.toBeNull();
				expect(data).not.toHaveProperty('key-d');
				expect(data).not.toHaveProperty('key-e');
				expect(data['key-e']).not.toBeType('object');
				expect(data).not.toHaveProperty('key-f');
				expect(data['key-f']).not.toBeType('boolean');
				this.disconnect();
			});
		});
	});

	it('should delete a nested object by path (array)', function(expect){
		expect.perform(28);
		var spy = new Spy();

		var first = io.connect(null, {'force new connection': 1});

		first.on('connect', function(){
			first.emit('put', {
				'key-a': {
					'key-a': 12,
					'key-b': 'ok',
					'key-c': null,
					'key-d': [],
					'key-e': {},
					'key-f': false
				}
			});
		});

		first.on('put', function(data){
			first.emit('delete', ['key-a', 'key-a']);
			first.emit('delete', ['key-a', 'key-b']);
			first.emit('delete', ['key-a', 'key-c']);
			first.emit('delete', ['key-a', 'key-d']);
			first.emit('delete', ['key-a', 'key-e']);
			first.emit('delete', ['key-a', 'key-f']);
			this.disconnect();
		});

		first.on('delete', function(key){
			spy();
			expect(key).toBeType('array');
			expect(key[0]).toBe('key-a');
			expect(key[1]).toMatch(/key-[a-f]/);
		});

		first.on('disconnect', function(data){

			var second = io.connect(null, {'force new connection': 1});

			second.on('get', function(data){
				expect(spy.getCallCount()).toBe(6);
				expect(data).toBeType('object');
				expect(data).toHaveProperty('key-a');
				expect(data['key-a']).toBeType('object');
				expect(data['key-a']).not.toHaveProperty('key-a');
				expect(data['key-a']).not.toHaveProperty('key-b');
				expect(data['key-a']).not.toHaveProperty('key-c');
				expect(data['key-a']).not.toHaveProperty('key-d');
				expect(data['key-a']).not.toHaveProperty('key-e');
				expect(data['key-a']).not.toHaveProperty('key-f');
				this.disconnect();
			});
		});

		// TODO: delete null
	});

});

};
<|endoftext|>


<commit_before>'use babel';

import * as path from 'path';
import { provideLinter } from '../lib/main';

const lint = provideLinter().lint;

const petstoreJSONPath = path.join(__dirname, 'fixtures', 'petstore.json');
const petstoreYAMLPath = path.join(__dirname, 'fixtures', 'petstore.yaml');
const petstoreBadref = path.join(__dirname, 'fixtures', 'petstore-badref.yaml');

describe('The Swagger provider for Linter', () => {
  describe('linting JSON files', () => {
    beforeEach(() => {
      atom.workspace.destroyActivePaneItem();
      waitsForPromise(() =>
        Promise.all([
          atom.packages.activatePackage('linter-swagger'),
          atom.packages.activatePackage('language-json'),
        ]).then(() =>
          atom.workspace.open(petstoreJSONPath)
        )
      );
    });

    it('finds nothing wrong with valid file', () => {
      waitsForPromise(() =>
        atom.workspace.open(petstoreJSONPath).then(editor =>
          lint(editor).then(messages =>
            expect(messages.length).toBe(0)
          )
        )
      );
    });
  });

  describe('linting YAML files', () => {
    beforeEach(() => {
      atom.workspace.destroyActivePaneItem();
      waitsForPromise(() =>
        Promise.all([
          atom.packages.activatePackage('linter-swagger'),
          atom.packages.activatePackage('language-yaml'),
        ]).then(() =>
          atom.workspace.open(petstoreYAMLPath)
        )
      );
    });

    describe('checks a file with issues', () => {
      let editor = null;

      beforeEach(() => {
        waitsForPromise(() =>
          atom.workspace.open(petstoreBadref).then((openEditor) => {
            editor = openEditor;
          })
        );
      });

      it('finds one message', () =>
        waitsForPromise(() =>
          lint(editor).then(messages =>
            expect(messages.length).toBe(1)
          )
        )
      );

      it('verifies the message', () => {
        /* eslint-disable no-useless-escape */
        const msgRegex = new RegExp('Error resolving \\$ref pointer ".+' +
          '#\/definitions\/INVALIDREFERENCE"\\.\\s+' +
          'Token "definitions" does not exist\\.', 'g');
        /* eslint-enable no-useless-escape */
        return waitsForPromise(() =>
          lint(editor).then((messages) => {
            expect(messages[0].type).toBe('Error');
            expect(messages[0].text).toMatch(msgRegex);
            expect(messages[0].filePath).toBe(petstoreBadref);
            expect(messages[0].range).toEqual([[0, 0], [0, 14]]);
          })
        );
      });
    });

    it('finds nothing wrong with a valid file', () =>
      waitsForPromise(() =>
        atom.workspace.open(petstoreYAMLPath).then(editor =>
          lint(editor).then((messages) => {
            expect(messages.length).toBe(0);
          })
        )
      )
    );
  });
});
<commit_msg>Cleanup specs a bit more<commit_after>'use babel';

import { join } from 'path';
import { provideLinter } from '../lib/main';

const lint = provideLinter().lint;

const petstoreJSONPath = join(__dirname, 'fixtures', 'petstore.json');
const petstoreYAMLPath = join(__dirname, 'fixtures', 'petstore.yaml');
const petstoreBadref = join(__dirname, 'fixtures', 'petstore-badref.yaml');

describe('The Swagger provider for Linter', () => {
  describe('linting JSON files', () => {
    beforeEach(() => {
      atom.workspace.destroyActivePaneItem();
      waitsForPromise(() =>
        Promise.all([
          atom.packages.activatePackage('linter-swagger'),
          atom.packages.activatePackage('language-json'),
        ])
      );
    });

    it('finds nothing wrong with valid file', () => {
      waitsForPromise(() =>
        atom.workspace.open(petstoreJSONPath).then(editor =>
          lint(editor).then(messages =>
            expect(messages.length).toBe(0)
          )
        )
      );
    });
  });

  describe('linting YAML files', () => {
    beforeEach(() => {
      atom.workspace.destroyActivePaneItem();
      waitsForPromise(() =>
        Promise.all([
          atom.packages.activatePackage('linter-swagger'),
          atom.packages.activatePackage('language-yaml'),
        ])
      );
    });

    describe('checks a file with issues', () => {
      let editor = null;

      beforeEach(() => {
        waitsForPromise(() =>
          atom.workspace.open(petstoreBadref).then((openEditor) => {
            editor = openEditor;
          })
        );
      });

      it('finds one message', () =>
        waitsForPromise(() =>
          lint(editor).then(messages =>
            expect(messages.length).toBe(1)
          )
        )
      );

      it('verifies the message', () => {
        /* eslint-disable no-useless-escape */
        const msgRegex = new RegExp('Error resolving \\$ref pointer ".+' +
          '#\/definitions\/INVALIDREFERENCE"\\.\\s+' +
          'Token "definitions" does not exist\\.', 'g');
        /* eslint-enable no-useless-escape */
        return waitsForPromise(() =>
          lint(editor).then((messages) => {
            expect(messages[0].type).toBe('Error');
            expect(messages[0].text).toMatch(msgRegex);
            expect(messages[0].filePath).toBe(petstoreBadref);
            expect(messages[0].range).toEqual([[0, 0], [0, 14]]);
          })
        );
      });
    });

    it('finds nothing wrong with a valid file', () =>
      waitsForPromise(() =>
        atom.workspace.open(petstoreYAMLPath).then(editor =>
          lint(editor).then((messages) => {
            expect(messages.length).toBe(0);
          })
        )
      )
    );
  });
});
<|endoftext|>


<commit_before>var jade = require('jade');
var mixin = require('utils-merge');
var stormpath = require('stormpath');

module.exports.render = function(view, res, options) {
  options = options || {};
  mixin(options, res.locals);

  jade.renderFile(view, options, function(err, html) {
    if (err) throw err;
    res.send(html);
  });
};

module.exports.getUser = function(req, res, callback) {
  if (req.session && req.session.user) {
    req.app.get('stormpathClient').getAccount(req.session.user.href, { expand: 'customData' }, function(err, account) {
      if (err) {
        req.session.reset();
      } else {
        req.session.user = account;
        res.locals.user = account;
      }
      callback();
    });
  } else {
    callback();
  }
};

module.exports.initSettings = function(app, opts) {
  return function(next) {
    // Basic credentials and configuration.
    app.set('stormpathApiKeyId', opts.apiKeyId || process.env.STORMPATH_API_KEY_ID);
    app.set('stormpathApiKeySecret', opts.apiKeySecret || process.env.STORMPATH_API_KEY_SECRET);
    app.set('stormpathApiKeyFile', opts.apiKeyFile || process.env.STORMPATH_API_KEY_FILE);
    app.set('stormpathApplication', opts.application || process.env.STORMPATH_APPLICATION);

    // Session configuration.
    app.set('stormpathSecretKey', opts.secretKey || process.env.STORMPATH_SECRET_KEY);
    app.set('stormpathEnableHttps', opts.enableHttps || process.env.STORMPATH_ENABLE_HTTPS || false);
    app.set('stormpathSessionDuration', opts.sessionDuration || parseInt(process.env.STORMPATH_SESSION_DURATION) || 1000 * 60 * 60 * 24 * 30);

    // Which fields should we display when registering new users?
    app.set('stormpathEnableUsername', opts.enableUsername || (process.env.STORMPATH_ENABLE_USERNAME === 'true') || false);
    app.set('stormpathEnableGivenName', opts.enableGivenName || (process.env.STORMPATH_ENABLE_GIVEN_NAME === 'true') || true);
    app.set('stormpathEnableMiddleName', opts.enableMiddleName || (process.env.STORMPATH_ENABLE_MIDDLE_NAME === 'true') || false);
    app.set('stormpathEnableSurname', opts.enableSurname || (process.env.STORMPATH_ENABLE_SURNAME === 'true') || true);
    app.set('stormpathEnableEmail', opts.enableEmail || (process.env.STORMPATH_ENABLE_EMAIL === 'true') || true);
    app.set('stormpathEnablePassword', opts.enablePassword || (process.env.STORMPATH_ENABLE_EMAIL === 'true') || true);

    // Which fields should we require when creating new users?
    app.set('stormpathRequireUsername', opts.requireUsername || (process.env.STORMPATH_REQUIRE_USERNAME === 'true') || false);
    app.set('stormpathRequireGivenName', opts.requireGivenName || (process.env.STORMPATH_REQUIRE_GIVEN_NAME === 'true') || true);
    app.set('stormpathRequireMiddleName', opts.requireMiddleName || (process.env.STORMPATH_REQUIRE_MIDDLE_NAME === 'true') || false);
    app.set('stormpathRequireSurname', opts.requireSurname || (process.env.STORMPATH_REQUIRE_SURNAME === 'true') || true);
    app.set('stormpathRequireEmail', opts.requireEmail || (process.env.STORMPATH_REQUIRE_EMAIL === 'true') || true);
    app.set('stormpathRequirePassword', opts.requirePassword || (process.env.STORMPATH_REQUIRE_PASSWORD === 'true') || true);

    // Which controllers should we enable?
    app.set('stormpathEnableRegistration', opts.enableRegistration || (process.env.STORMPATH_ENABLE_REGISTRATION === 'true') || true);
    app.set('stormpathEnableLogin', opts.enableLogin || (process.env.STORMPATH_ENABLE_LOGIN === 'true') || true);
    app.set('stormpathEnableLogout', opts.enableLogout || (process.env.STORMPATH_ENABLE_LOGOUT === 'true') || true);

    // Which views should we render?
    app.set('stormpathRegistrationView', opts.registrationView || process.env.STORMPATH_REGISTRATION_VIEW || __dirname + '/views/register.jade');
    app.set('stormpathLoginView', opts.loginView || process.env.STORMPATH_LOGIN_VIEW || __dirname + '/views/login.jade');

    // Routing configuration.
    app.set('stormpathRegistrationUrl', opts.registrationUrl || process.env.STORMPATH_REGISTRATION_URL || '/register');
    app.set('stormpathLoginUrl', opts.loginUrl || process.env.STORMPATH_LOGIN_URL || '/login');
    app.set('stormpathLogoutUrl', opts.logoutUrl || process.env.STORMPATH_LOGOUT_URL || '/logout');
    app.set('stormpathRedirectUrl', opts.redirectUrl || process.env.STORMPATH_REDIRECT_URL || '/');

    next();
  };
};

module.exports.checkSettings = function(app) {
  return function(next) {
    if (!app.get('stormpathSecretKey')) {
      throw new Error('ERROR: No Stormpath secretKey specified.');
    }

    if (!(
      (app.get('stormpathApiKeyID') && app.get('stormpathApiKeySecret')) ||
      app.get('stormpathApiKeyFile')
    )) {
      throw new Error('ERROR: No Stormpath credentials specified.');
    }

    if (!app.get('stormpathApplication')) {
      throw new Error('ERROR: No Stormpath application specified.');
    }

    next();
  };
};
<commit_msg>Auto-expanding groups.<commit_after>var jade = require('jade');
var mixin = require('utils-merge');
var stormpath = require('stormpath');

module.exports.render = function(view, res, options) {
  options = options || {};
  mixin(options, res.locals);

  jade.renderFile(view, options, function(err, html) {
    if (err) throw err;
    res.send(html);
  });
};

module.exports.getUser = function(req, res, callback) {
  if (req.session && req.session.user) {
    req.app.get('stormpathClient').getAccount(req.session.user.href, { expand: 'customData,groups' }, function(err, account) {
      if (err) {
        req.session.reset();
      } else {
        req.session.user = account;
        res.locals.user = account;
      }
      callback();
    });
  } else {
    callback();
  }
};

module.exports.initSettings = function(app, opts) {
  return function(next) {
    // Basic credentials and configuration.
    app.set('stormpathApiKeyId', opts.apiKeyId || process.env.STORMPATH_API_KEY_ID);
    app.set('stormpathApiKeySecret', opts.apiKeySecret || process.env.STORMPATH_API_KEY_SECRET);
    app.set('stormpathApiKeyFile', opts.apiKeyFile || process.env.STORMPATH_API_KEY_FILE);
    app.set('stormpathApplication', opts.application || process.env.STORMPATH_APPLICATION);

    // Session configuration.
    app.set('stormpathSecretKey', opts.secretKey || process.env.STORMPATH_SECRET_KEY);
    app.set('stormpathEnableHttps', opts.enableHttps || process.env.STORMPATH_ENABLE_HTTPS || false);
    app.set('stormpathSessionDuration', opts.sessionDuration || parseInt(process.env.STORMPATH_SESSION_DURATION) || 1000 * 60 * 60 * 24 * 30);

    // Which fields should we display when registering new users?
    app.set('stormpathEnableUsername', opts.enableUsername || (process.env.STORMPATH_ENABLE_USERNAME === 'true') || false);
    app.set('stormpathEnableGivenName', opts.enableGivenName || (process.env.STORMPATH_ENABLE_GIVEN_NAME === 'true') || true);
    app.set('stormpathEnableMiddleName', opts.enableMiddleName || (process.env.STORMPATH_ENABLE_MIDDLE_NAME === 'true') || false);
    app.set('stormpathEnableSurname', opts.enableSurname || (process.env.STORMPATH_ENABLE_SURNAME === 'true') || true);
    app.set('stormpathEnableEmail', opts.enableEmail || (process.env.STORMPATH_ENABLE_EMAIL === 'true') || true);
    app.set('stormpathEnablePassword', opts.enablePassword || (process.env.STORMPATH_ENABLE_EMAIL === 'true') || true);

    // Which fields should we require when creating new users?
    app.set('stormpathRequireUsername', opts.requireUsername || (process.env.STORMPATH_REQUIRE_USERNAME === 'true') || false);
    app.set('stormpathRequireGivenName', opts.requireGivenName || (process.env.STORMPATH_REQUIRE_GIVEN_NAME === 'true') || true);
    app.set('stormpathRequireMiddleName', opts.requireMiddleName || (process.env.STORMPATH_REQUIRE_MIDDLE_NAME === 'true') || false);
    app.set('stormpathRequireSurname', opts.requireSurname || (process.env.STORMPATH_REQUIRE_SURNAME === 'true') || true);
    app.set('stormpathRequireEmail', opts.requireEmail || (process.env.STORMPATH_REQUIRE_EMAIL === 'true') || true);
    app.set('stormpathRequirePassword', opts.requirePassword || (process.env.STORMPATH_REQUIRE_PASSWORD === 'true') || true);

    // Which controllers should we enable?
    app.set('stormpathEnableRegistration', opts.enableRegistration || (process.env.STORMPATH_ENABLE_REGISTRATION === 'true') || true);
    app.set('stormpathEnableLogin', opts.enableLogin || (process.env.STORMPATH_ENABLE_LOGIN === 'true') || true);
    app.set('stormpathEnableLogout', opts.enableLogout || (process.env.STORMPATH_ENABLE_LOGOUT === 'true') || true);

    // Which views should we render?
    app.set('stormpathRegistrationView', opts.registrationView || process.env.STORMPATH_REGISTRATION_VIEW || __dirname + '/views/register.jade');
    app.set('stormpathLoginView', opts.loginView || process.env.STORMPATH_LOGIN_VIEW || __dirname + '/views/login.jade');

    // Routing configuration.
    app.set('stormpathRegistrationUrl', opts.registrationUrl || process.env.STORMPATH_REGISTRATION_URL || '/register');
    app.set('stormpathLoginUrl', opts.loginUrl || process.env.STORMPATH_LOGIN_URL || '/login');
    app.set('stormpathLogoutUrl', opts.logoutUrl || process.env.STORMPATH_LOGOUT_URL || '/logout');
    app.set('stormpathRedirectUrl', opts.redirectUrl || process.env.STORMPATH_REDIRECT_URL || '/');

    next();
  };
};

module.exports.checkSettings = function(app) {
  return function(next) {
    if (!app.get('stormpathSecretKey')) {
      throw new Error('ERROR: No Stormpath secretKey specified.');
    }

    if (!(
      (app.get('stormpathApiKeyID') && app.get('stormpathApiKeySecret')) ||
      app.get('stormpathApiKeyFile')
    )) {
      throw new Error('ERROR: No Stormpath credentials specified.');
    }

    if (!app.get('stormpathApplication')) {
      throw new Error('ERROR: No Stormpath application specified.');
    }

    next();
  };
};
<|endoftext|>


<commit_before>const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

function minify(doMinify) {
  return { mode: doMinify ? 'production' : 'none' }
}

function file(srcPath, output) {
  let parsedOutput = path.parse(output)
  let entryName = parsedOutput.name // foo.js => foo
  let outputFilename = parsedOutput.base
  let outputFolder = parsedOutput.dir || (__dirname + '/../dist')

  return {
    entry: {
      [entryName]: srcPath
    },
    output: {
      path: outputFolder,
      filename: outputFilename,
    },
    devServer: {
      contentBase: './dist',
      writeToDisk: true,
    },
    cache: true
  }
}

function scriptPipeline(target) {
  if (target === 'modern') {
    target = 'es2020'
  }

  let erbLoader = {
    loader: 'rails-erb-loader',
    options: {
      runner: 'ruby',
      engine: 'erb',
    }
  }

  let tsLoader = {
    loader: 'ts-loader',
    options: {
      appendTsSuffixTo: [/.*/],
      transpileOnly: true,
      compilerOptions: {
        allowJs: true,
        checkJs: true,
        // importHelpers: true,
        // module: "ES2020",
        target: target
      }

    }
  }

  let coffeeLoader = {
    loader: 'coffee-loader'
  }

  return {
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [tsLoader]
        },
        {
          test: /\.coffee$/,
          exclude: /node_modules/,
          use: [tsLoader, coffeeLoader]
        },
        {
          test: /\.js\.erb$/,
          exclude: /node_modules/,
          use: [tsLoader, erbLoader]
        },
        {
          test: /\.coffee\.erb$/,
          exclude: /node_modules/,
          use: [tsLoader, coffeeLoader, erbLoader]
        }
      ]
    },
    resolve: {
      extensions: ['.js', '.coffee', '.js.erb', '.coffee.erb']
    }
  }
}

function merge(...configs) {
  let merged = {
    module: {
      rules: []
    },
    resolve: {
      extensions: []
    },
    plugins: []
  }

  for (let config of configs) {
    if (!config) {
      // Skip null configs
      continue
    }

    // First set all the config keys that never existed in merged
    for (let key in config) {
      if (merged[key] == null) {
        merged[key] = config[key]
      }
    }

    // Now merge all keys with array values
    if (config.module && config.module.rules) {
      merged.module.rules.push(...config.module.rules)
    }
    if (config.resolve && config.resolve.extensions) {
      merged.resolve.extensions.push(...config.resolve.extensions)
    }
    if (config.plugins) {
      merged.plugins.push(...config.plugins)
    }
  }

  return merged
}

let extractCssLoader = {
  loader: MiniCssExtractPlugin.loader,
  options: {
    hmr: false
  }
}

stylePipeline = function(filename = "[name.css]") {
  return {
    plugins: [
      new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // all options are optional
        filename,
        chunkFilename: '[id].css',
        ignoreOrder: false, // Enable to remove warnings about conflicting order
      })
    ],
    module: {
      rules: [
        {
          test: /\.(css)$/,
          use: [extractCssLoader, 'css-loader']
        },
        {
          test: /\.(sass|scss)$/,
          use: [extractCssLoader, 'css-loader', 'sass-loader']
        },
      ],
    },
    resolve: {
      extensions: ['.css', '.sass', '.scss']
    }
  }
}

discardStyles = function() {
  return {
    module: {
      rules: [
        {
          test: /\.(css|sass|scss)$/,
          use: 'null-loader'
        },
      ],
    },
    resolve: {
      extensions: ['.css', '.sass', '.scss']
    }
  }
}

module.exports = {
  merge,
  file,
  scriptPipeline,
  stylePipeline,
  discardStyles,
  minify
}
<commit_msg>Respect ES target for Webpack module registry boilerplate<commit_after>const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

function minify(doMinify) {
  return { mode: doMinify ? 'production' : 'none' }
}

function file(srcPath, output) {
  let parsedOutput = path.parse(output)
  let entryName = parsedOutput.name // foo.js => foo
  let outputFilename = parsedOutput.base
  let outputFolder = parsedOutput.dir || (__dirname + '/../dist')

  return {
    entry: {
      [entryName]: srcPath
    },
    output: {
      path: outputFolder,
      filename: outputFilename,
    },
    devServer: {
      contentBase: './dist',
      writeToDisk: true,
    },
    cache: true
  }
}

function scriptPipeline(target) {
  if (target === 'modern') {
    target = 'es2020'
  }

  let erbLoader = {
    loader: 'rails-erb-loader',
    options: {
      runner: 'ruby',
      engine: 'erb',
    }
  }

  let tsLoader = {
    loader: 'ts-loader',
    options: {
      appendTsSuffixTo: [/.*/],
      transpileOnly: true,
      compilerOptions: {
        allowJs: true,
        checkJs: true,
        // importHelpers: true,
        // module: "ES2020",
        target: target
      }

    }
  }

  let coffeeLoader = {
    loader: 'coffee-loader'
  }

  return {
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [tsLoader]
        },
        {
          test: /\.coffee$/,
          exclude: /node_modules/,
          use: [tsLoader, coffeeLoader]
        },
        {
          test: /\.js\.erb$/,
          exclude: /node_modules/,
          use: [tsLoader, erbLoader]
        },
        {
          test: /\.coffee\.erb$/,
          exclude: /node_modules/,
          use: [tsLoader, coffeeLoader, erbLoader]
        }
      ]
    },
    resolve: {
      extensions: ['.js', '.coffee', '.js.erb', '.coffee.erb']
    },
    target: ['web', target]
  }
}

function merge(...configs) {
  let merged = {
    module: {
      rules: []
    },
    resolve: {
      extensions: []
    },
    plugins: []
  }

  for (let config of configs) {
    if (!config) {
      // Skip null configs
      continue
    }

    // First set all the config keys that never existed in merged
    for (let key in config) {
      if (merged[key] == null) {
        merged[key] = config[key]
      }
    }

    // Now merge all keys with array values
    if (config.module && config.module.rules) {
      merged.module.rules.push(...config.module.rules)
    }
    if (config.resolve && config.resolve.extensions) {
      merged.resolve.extensions.push(...config.resolve.extensions)
    }
    if (config.plugins) {
      merged.plugins.push(...config.plugins)
    }
  }

  return merged
}

let extractCssLoader = {
  loader: MiniCssExtractPlugin.loader,
  options: {
    hmr: false
  }
}

stylePipeline = function(filename = "[name.css]") {
  return {
    plugins: [
      new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // all options are optional
        filename,
        chunkFilename: '[id].css',
        ignoreOrder: false, // Enable to remove warnings about conflicting order
      })
    ],
    module: {
      rules: [
        {
          test: /\.(css)$/,
          use: [extractCssLoader, 'css-loader']
        },
        {
          test: /\.(sass|scss)$/,
          use: [extractCssLoader, 'css-loader', 'sass-loader']
        },
      ],
    },
    resolve: {
      extensions: ['.css', '.sass', '.scss']
    }
  }
}

discardStyles = function() {
  return {
    module: {
      rules: [
        {
          test: /\.(css|sass|scss)$/,
          use: 'null-loader'
        },
      ],
    },
    resolve: {
      extensions: ['.css', '.sass', '.scss']
    }
  }
}

module.exports = {
  merge,
  file,
  scriptPipeline,
  stylePipeline,
  discardStyles,
  minify
}
<|endoftext|>


<commit_before>const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const Marked = CompLibrary.Marked; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;
const Prism = CompLibrary.Prism;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (

        <a className={`button ${this.props.className || ""}`} href={this.props.href} target={this.props.target}>
          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self"
};

const codeExample =`let component = ReasonReact.statelessComponent "Greeting";

let make ::name _children => {
  ...component,
  render: fun _self =>
    <button>
      (ReasonReact.stringToElement "Hello!")
    </button>
};`;

const pre = "```";
const code = "`";
const quickStart = `${pre}bash
npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app
npm install && npm start
${pre}

Then open another tab and do:

${pre}bash
npm run build
${pre}

Your apps are the html files inside ${code}src/${code}`;

class HomeSplash extends React.Component {
  render() {
    let promoSection =
      <div className="section promoSection">
        <div className="promoRow">
          <div className="pluginRowBlock">
            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/installation.html"
              }
            >
              <translate>Get Started</translate>
            </Button>
            <Button
              href="https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial"
            >
              Tutorial
            </Button>
          </div>
        </div>
      </div>;

    return (
      <div className="homeContainer">

        <div id="redirectBanner">
          <div>
            Hello! This particular page hash has moved to <a id="redirectLink"/>.
            Please update the URLs to reflect it. Thanks!
          </div>
        </div>

        <div className="homeWrapperWrapper">

          <img src={siteConfig.baseUrl + siteConfig.headerIcon} className="spinner" />

          <div className="wrapper homeWrapper">
            <div className="projectTitle">{siteConfig.title}</div>

            <div className="homeWrapperInner">
              <div className="homeTagLine">{siteConfig.tagline}</div>
              <div className="homeCodeSnippet">
                <Prism>{codeExample}</Prism>
              </div>
            </div>

            {promoSection}
          </div>

        </div>
      </div>
    );
  }
}

class Index extends React.Component {
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (
          <a href={user.infoLink}>
            <img src={`${siteConfig.baseUrl}${user.image}`} title={user.caption} />
          </a>
        );
      });

    return (
      <div>
        <HomeSplash language={language} />
        <div className="mainContainer">
          <Container className="homeThreePoints" padding={["bottom"]}>
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>

          <Container background="light" className="quickStartAndExamples homeCodeSnippet">
            <div>
              <h2>Quick Start</h2>
              <Marked>
                {quickStart}
              </Marked>
            </div>
            <div>
              <h2>Examples</h2>
              <GridBlock
                className="examples"
                align="center"
                contents={siteConfig.examples.map(example => ({
                  title: example.name,
                  image: example.image,
                  imageLink: example.link,
                  imageAlign: "top",
                  content: "",
                }))}
                layout="twoColumn"
              />
          </div>
          </Container>

          <div className="productShowcaseSection paddingBottom">
            <h2>
              <translate>Projects Using ReasonReact</translate>
            </h2>
            <div className="logos">
              {showcase}
            </div>
            <div className="more-users">
              <a
                className="button"
                href={`${siteConfig.baseUrl}${this.props.language}/built-with-reason-react.html`}
              >
                <translate>See Full List</translate>
              </a>
            </div>
          </div>
        </div>
        <script src={siteConfig.baseUrl + 'js/redirectIndex.js'}></script>
      </div>
    );
  }
}

module.exports = Index;
<commit_msg>Fix i18n pages image links<commit_after>const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const Marked = CompLibrary.Marked; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;
const Prism = CompLibrary.Prism;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (
      <div className="pluginWrapper">
        <a className={`button ${this.props.className || ""}`} href={this.props.href} target={this.props.target}>
          {this.props.children}
        </a>
      </div>
    );
  }
}

Button.defaultProps = {
  target: "_self"
};

const codeExample =`let component = ReasonReact.statelessComponent "Greeting";

let make ::name _children => {
  ...component,
  render: fun _self =>
    <button>
      (ReasonReact.stringToElement "Hello!")
    </button>
};`;

const pre = "```";
const code = "`";
const quickStart = `${pre}bash
npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app
npm install && npm start
${pre}

Then open another tab and do:

${pre}bash
npm run build
${pre}

Your apps are the html files inside ${code}src/${code}`;

class HomeSplash extends React.Component {
  render() {
    let promoSection =

            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/installation.html"
              }
            >
              <translate>Get Started</translate>
            </Button>
            <Button
              href="https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial"
            >
              Tutorial
            </Button>

;

    return (

            Hello! This particular page hash has moved to .
            Please update the URLs to reflect it. Thanks!

{siteConfig.title}

{siteConfig.tagline}

                <Prism>{codeExample}</Prism>

            {promoSection}

    );
  }
}

class Index extends React.Component {
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (

            <img src={`${siteConfig.baseUrl}${user.image}`} title={user.caption} />

        );
      });

    return (

        <HomeSplash language={language} />

          <Container className="homeThreePoints" padding={["bottom"]}>
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>

          <Container background="light" className="quickStartAndExamples homeCodeSnippet">

Quick Start

              <Marked>
                {quickStart}
              </Marked>

Examples

              <GridBlock
                className="examples"
                align="center"
                contents={siteConfig.examples.map(example => ({
                  title: example.name,
                  image: example.image,
                  imageLink: `${siteConfig.baseUrl}${example.link}`,
                  imageAlign: "top",
                  content: "",
                }))}
                layout="twoColumn"
              />

          </Container>

              <translate>Projects Using ReasonReact</translate>

              {showcase}

              <a
                className="button"
                href={`${siteConfig.baseUrl}${this.props.language}/built-with-reason-react.html`}
              >
                <translate>See Full List</translate>

    );
  }
}

module.exports = Index;
<|endoftext|>


<commit_before>import React from 'react'
import Spinner from 'react-spinner'

import api from '../lib/api'

import PhotoCredit from './PhotoCredit'
import { fileToDataURL } from '../lib/util'

export const downloadThumbnailImage = img => {
  return api.client
    .get(img.url.replace('http://', 'https://'), { responseType: 'blob' })
    .then(res => res.data)
    .then(fileToDataURL)
    .then(dataURL => Object.assign(img, { dataURL }))
}

const getImageDownloadUrl = img =>
  api.client.get(`/unsplash/download/${img.id}`).then(res => res.data.url)

class RandomImage extends React.Component {
  constructor(props) {
    super(props)
    this.state = { cacheIndex: 0, loading: false }
    this.selectImage = this.selectImage.bind(this)
    this.updateCache = this.updateCache.bind(this)
    this.getImages = this.getImages.bind(this)
    this.nextImage = this.nextImage.bind(this)
  }

  cache = []

  // fetch images in browser (we require window.FileReader)
  componentDidMount() {
    // clear cache when remounted
    this.cache = []
    this.updateCache()
  }

  async getImages() {
    const imageUrls = await api.client.get('/unsplash/random')
    return Promise.all(imageUrls.data.map(downloadThumbnailImage))
  }

  selectImage() {
    if (this.state.loading) {
      return
    }

    const image = this.cache[this.state.cacheIndex]

    this.setState({ loading: true })
    getImageDownloadUrl(image)
      .then(url => api.client.get(url, { responseType: 'blob' }))
      .then(res => res.data)
      .then(blob => this.props.onChange(blob, image))
      .then(() => this.setState({ loading: false }))
  }

  updateCache() {
    this.setState({ loading: true })
    this.getImages()
      .then(imgs => (this.cache = this.cache.concat(imgs)))
      .then(() => this.setState({ loading: false }))
  }

  nextImage() {
    if (this.state.loading) {
      return
    }

    this.setState(state => ({ cacheIndex: state.cacheIndex + 1 }))

    if (this.state.cacheIndex > this.cache.length - 2) {
      this.updateCache()
    }
  }

  render() {
    const photographer =
      this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].photographer
    const bgImage = this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].dataURL

    return (

            Use Image

            Try Another

{this.state.loading && <Spinner />}

        {photographer && <PhotoCredit photographer={photographer} />}

    )
  }
}

export default RandomImage
<commit_msg>use hooks for RandomImage<commit_after>import React from 'react'
import Spinner from 'react-spinner'
import { useAsyncCallback } from '@dawnlabs/tacklebox'

import api from '../lib/api'

import PhotoCredit from './PhotoCredit'
import { fileToDataURL } from '../lib/util'

export const downloadThumbnailImage = img => {
  return api.client
    .get(img.url.replace('http://', 'https://'), { responseType: 'blob' })
    .then(res => res.data)
    .then(fileToDataURL)
    .then(dataURL => Object.assign(img, { dataURL }))
}

const getImageDownloadUrl = img =>
  api.client.get(`/unsplash/download/${img.id}`).then(res => res.data.url)

async function getImages() {
  const imageUrls = await api.client.get('/unsplash/random')
  return Promise.all(imageUrls.data.map(downloadThumbnailImage))
}

function RandomImage(props) {
  const { current: cache } = React.useRef([])
  const [cacheIndex, updateIndex] = React.useState(0)

  const [selectImage, { loading: selecting }] = useAsyncCallback(() => {
    const image = cache[cacheIndex]

    return getImageDownloadUrl(image)
      .then(url => api.client.get(url, { responseType: 'blob' }))
      .then(res => res.data)
      .then(blob => props.onChange(blob, image))
  })

  const [updateCache, { loading: updating, data: imgs }] = useAsyncCallback(getImages)

  React.useEffect(() => {
    if (cacheIndex === 0 || cacheIndex > cache.length - 2) {
      updateCache()
    }
  }, [cacheIndex])

  React.useEffect(() => {
    if (imgs) {
      cache.push(...imgs)
    }
  }, [imgs])

  const loading = updating || selecting

  const photographer = cache[cacheIndex] && cache[cacheIndex].photographer
  const bgImage = cache[cacheIndex] && cache[cacheIndex].dataURL
  return (

          Use Image

         updateIndex(i => i + 1)}>
          Try Another

{loading && <Spinner />}

      {photographer && <PhotoCredit photographer={photographer} />}

  )
}

export default RandomImage
<|endoftext|>


<commit_before>/** Group information */
var group;
var settings;
var accessType;

/** Access and membership settings checkbox table */
var accessSettingsChecked;
var membershipSettingsChecked;

async function onloadGroupDetails() {
    checkLoginAndSetUp();

    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    var groupId = urlParams.get('group');

    Promise.all([getAllGroups(true), getAllUsers()])
    .then(async function(results) {
        group = await getGroup(groupId);
        loadGroup();
    })
}

/** Load the group into data for d3 */
async function loadGroup() {
    isLoading = true;
    setLoadingOverlay();

    // reset data and unique users
    usersDisplayed = [];
    data = {
            name: domain,
            children: [],
        };
    // create the visited hash set for groups already processed, containing group IDs
    visited = {};
    members = {};

    // collect all the promises
    var promises = [];
    for (g of groups) {
        // iterate through all the groups and get their direct members
        promises.push(getGroupMembers(g.id));
    }

    Promise.all(promises)
    .then(async function(results) {
        var newData = await loadGroupsDFS(group, null, groups, users, members);
        data.children.push(newData);

        visualize();
        loadGroupDetailsSidebar();
    })
}

/** Fill in informational fields on the sidebar of the page */
function loadGroupDetailsSidebar() {
    setGroupInformation();
    setGroupSettings();
}

/** Set group information for specific group */
function setGroupInformation() {
    document.getElementById("group-name-title").innerHTML = group.name;
    document.getElementById("group-name").innerHTML = group.name;
    document.getElementById("group-email").innerHTML = group.email;

    var groupDescription = document.getElementById("group-description");
    if (group.description) groupDescription.innerHTML = group.description;

    document.getElementById("num-groups").innerHTML = Object.keys(visited).length;
    document.getElementById("num-users").innerHTML = usersDisplayed.length;
}

/** Set group settings for specific group */
async function setGroupSettings() {
    const response = await fetch('https://www.googleapis.com/groups/v1/groups/'
    + group.email + "?alt=json", {
        headers: {
            'authorization': `Bearer ` + token,
        }
    })
    const accessSettingsJson = await response.json();
    console.log(accessSettingsJson)

    if (response.status == 200) {
        settings = accessSettingsJson;

        document.getElementById("access-type").innerHTML = getAccessType(accessSettingsJson);
        document.getElementById("join-group").innerHTML = accessSettingsJson.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "Anyone in the organization can join" : accessSettingsJson.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "Anyone in the organization can ask" : "Only invited users";
        document.getElementById("members-outside-org").innerHTML = accessSettingsJson.allowExternalMembers == "true" ? "Yes" : "No";

        setAccessMembershipSettingsTable(accessSettingsJson);
    }
}

/** Returns the access type based on this group's settings */
function getAccessType(settings) {
    if (Object.keys(diff(settings, publicSettings)).length == 0) {
        accessType = "Public";
    } else if (Object.keys(diff(settings, teamSettings)).length == 0) {
        accessType = "Team";
    } else if (Object.keys(diff(settings, announcementOnlySettings)).length == 0) {
        accessType = "Announcement Only";
    } else if (Object.keys(diff(settings, restrictedSettings)).length == 0) {
        accessType = "Restricted";
    } else {
        accessType = "Custom";
    }
    return accessType;
}

/** Returns an object containing the key and value pairs for each difference between two objects
  * obj1: object you are comparing to default
  * obj2: default object
 */
function diff(obj1, obj2) {
    var diffs = {};
    for (key in obj2) {
        if (obj2.hasOwnProperty(key)) {
            if (obj1[key] !== obj2[key]) {
                diffs[key] = obj1[key];
            }
        }
    }
    return diffs;
}

/** Function called when user clicks to view access and membership settings */
function viewSettings() {
    hideElements(["view-settings-link"])
    showElements(["group-settings-chart", "hide-settings-link"])
}

/** Function called when user clicks to view access and membership settings */
function hideSettings() {
    showElements(["view-settings-link"])
    hideElements(["group-settings-chart", "hide-settings-link"])
}

/** Fills in the checkbox table for access and membership settings */
function setAccessMembershipSettingsTable(accessSettingsJson) {
    setAllCheckBoxesFalse(); // assume that all check box values should be overriden
    setCheckBoxesTrue(whoCanContactOwnerCheckboxMap[accessSettingsJson.whoCanContactOwner]);
    setCheckBoxesTrue(whoCanViewMembershipCheckboxMap[accessSettingsJson.whoCanViewMembership]);
    setCheckBoxesTrue(whoCanViewGroupCheckboxMap[accessSettingsJson.whoCanViewGroup]);
    setCheckBoxesTrue(whoCanPostMessageCheckboxMap[accessSettingsJson.whoCanPostMessage]);
    setCheckBoxesTrue(whoCanModifyMembersCheckboxMap[accessSettingsJson.whoCanModifyMembers]);
}

/** sets all check boxes for groups settings to false */
function setAllCheckBoxesFalse() {
    for (checkBox of document.getElementsByClassName("table-checkbox-input")) {
        checkBox.checked = false;
    }
}

/** sets check boxes true */
function setCheckBoxesTrue(checkBoxes) {
    for (checkBoxId of checkBoxes) {
        document.getElementById(checkBoxId).checked = true;
    }
}

/** Shows the edit fields for the information section */
function showEditInformationForm() {
    hideElements(["view-information-form", "show-edit-information-form"]);
    showElements(["edit-information-form", "save-information-form", "close-edit-information-form"]);

    document.getElementById("group-name-field").value = group.name;
    document.getElementById("group-email-field").value = group.email.split("@")[0];
    document.getElementById("group-email-domain").innerHTML = "@" + domain;

    var groupDescription = document.getElementById("group-description-field");
    if (group.description) groupDescription.value = group.description;
}

/** Saves the edit fields for the information section */
async function saveInformationForm() {
    isLoading = true;
    setLoadingOverlay();

    var groupName = document.getElementById("group-name-field").value;
    var groupEmail = document.getElementById("group-email-field").value;
    var groupDescription = document.getElementById("group-description-field").value;

    const response = await fetch('https://www.googleapis.com/admin/directory/v1/groups/'
    + group.id, {
        headers: {
            'authorization': `Bearer ` + token,
            'Content-Type': 'application/json'
        },
        method: 'PUT',
        body: JSON.stringify({"name": groupName, "email": groupEmail + "@" + domain, "description": groupDescription})
    })
    const groupJson = await response.json();
    console.log(groupJson)

    if (response.status == 200) {
        group = groupJson;
        setGroupInformation();
        closeInformationForm();
        isLoading = false;
        setLoadingOverlay();
    }
}

/** Hides the edit fields for the information section without saving */
function closeInformationForm() {
    showElements(["view-information-form", "show-edit-information-form"]);
    hideElements(["edit-information-form", "save-information-form", "close-edit-information-form"]);
}

/** Shows the edit fields for the settings section */
function showEditSettingsForm() {
    hideElements(["show-edit-settings-form", "access-type", "join-group", "members-outside-org"]);
    showElements(["save-settings-form", "close-edit-settings-form", "access-type-radio-group", "join-group-sel-group", "members-outside-org-switch-group", "save-settings-label"]);

    // Set values based on current group settings
    document.getElementById("access-type-radio-" + accessType.replace(/ /g, '-').toLowerCase()).checked = true;
    document.getElementById("join-group-sel").value = settings.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "anyone-can-join" : settings.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "anyone-can-ask" : "only-invited";
    document.getElementById("members-outside-org-switch").checked = settings.allowExternalMembers == "true" ? true : false;
}

/** Saves the edit fields for the settings section */
async function saveSettingsForm() {
    isLoading = true;
    setLoadingOverlay();

    var newPartialSettings = selectAccessType();
    var newSettings = Object.assign(settings, newPartialSettings);

    const response = await fetch('https://www.googleapis.com/groups/v1/groups/'
    + group.email, {
        headers: {
            'authorization': `Bearer ` + token,
            'Content-Type': 'application/json'
        },
        method: 'PUT',
        body: JSON.stringify(newSettings)
    })
    const accessSettingsJson = await response.json();
    console.log(accessSettingsJson)

    if (response.status == 200) {
        settings = accessSettingsJson;
        setGroupSettings();
        closeSettingsForm();
        isLoading = false;
        setLoadingOverlay();
    }
}

/** Hides the edit fields for the settings section without saving */
function closeSettingsForm() {
    showElements(["show-edit-settings-form", "access-type", "join-group", "members-outside-org"]);
    hideElements(["save-settings-form", "close-edit-settings-form", "access-type-radio-group", "join-group-sel-group", "members-outside-org-switch-group", "save-settings-label"]);

    // Reset checkboxes to original settings
    setAccessMembershipSettingsTable(settings);
}

/** Function called when user selects a new access type */
function selectAccessType() {
    var accessTypeSelected = document.querySelector('input[name="access-type-radio"]:checked').value;
    // Select all the checkboxes that correspond to this access type
    var newSettings;
    if (accessTypeSelected == "public") {
        newSettings = publicSettings;
    } else if (accessTypeSelected == "team") {
        newSettings = teamSettings;
    } else if (accessTypeSelected == "announcement-only") {
        newSettings = announcementOnlySettings;
    } else if (accessTypeSelected == "restricted") {
        newSettings = restrictedSettings;
    } else {
        return;
    }

    document.getElementById("join-group-sel").value = newSettings.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "anyone-can-join" : newSettings.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "anyone-can-ask" : "only-invited";
    document.getElementById("members-outside-org-switch").checked = newSettings.allowExternalMembers == "true" ? true : false;

    setAccessMembershipSettingsTable(newSettings);
    return newSettings;
}

/** Deletes the current group */
async function deleteGroup() {
    isLoading = true;
    setLoadingOverlay();

    const response = await fetch('https://www.googleapis.com/admin/directory/v1/groups/'
    + group.id, {
        headers: {
            'authorization': `Bearer ` + token
        },
        method: 'DELETE',
    })
    if (response.status == 200 || response.status == 204) {
        isLoading = false;
        setLoadingOverlay();
        window.location.href = "groups.html";
    }
}

/** Double checks that the user wants to delete this group */
function deleteGroupModal() {
    $('#deleteModal').modal('show');
}
<commit_msg>undo the pull request from group-details-script.js to prevent conflicts<commit_after>/** Group information */
var group;
var settings;
var accessType;

/** Access and membership settings checkbox table */
var accessSettingsChecked;
var membershipSettingsChecked;

async function onloadGroupDetails() {
    checkLoginAndSetUp();

    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    var groupId = urlParams.get('group');

    Promise.all([getAllGroups(true), getAllUsers()])
    .then(async function(results) {
        group = await getGroup(groupId);
        loadGroup();
    })
}

/** Load the group into data for d3 */
async function loadGroup() {
    isLoading = true;
    setLoadingOverlay();

    // reset data and unique users
    usersDisplayed = [];
    data = {
            name: domain,
            children: [],
        };
    // create the visited hash set for groups already processed, containing group IDs
    visited = {};
    members = {};

    // collect all the promises
    var promises = [];
    for (group of groups) {
        // iterate through all the groups and get their direct members
        promises.push(getGroupMembers(group.id));
    }

    Promise.all(promises)
    .then(async function(results) {
        var newData = await loadGroupsDFS(group);
        data.children.push(newData);

        visualize();
        loadGroupDetailsSidebar();
    })
}

/** Fill in informational fields on the sidebar of the page */
function loadGroupDetailsSidebar() {
    setGroupInformation();
    setGroupSettings();
}

/** Set group information for specific group */
function setGroupInformation() {
    document.getElementById("group-name-title").innerHTML = group.name;
    document.getElementById("group-name").innerHTML = group.name;
    document.getElementById("group-email").innerHTML = group.email;

    var groupDescription = document.getElementById("group-description");
    if (group.description) groupDescription.innerHTML = group.description;

    document.getElementById("num-groups").innerHTML = Object.keys(visited).length;
    document.getElementById("num-users").innerHTML = usersDisplayed.length;
}

/** Set group settings for specific group */
async function setGroupSettings() {
    const response = await fetch('https://www.googleapis.com/groups/v1/groups/'
    + group.email + "?alt=json", {
        headers: {
            'authorization': `Bearer ` + token,
        }
    })
    const accessSettingsJson = await response.json();
    console.log(accessSettingsJson)

    if (response.status == 200) {
        settings = accessSettingsJson;

        document.getElementById("access-type").innerHTML = getAccessType(accessSettingsJson);
        document.getElementById("join-group").innerHTML = accessSettingsJson.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "Anyone in the organization can join" : accessSettingsJson.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "Anyone in the organization can ask" : "Only invited users";
        document.getElementById("members-outside-org").innerHTML = accessSettingsJson.allowExternalMembers == "true" ? "Yes" : "No";

        setAccessMembershipSettingsTable(accessSettingsJson);
    }
}

/** Returns the access type based on this group's settings */
function getAccessType() {
    if (Object.keys(diff(settings, publicSettings)).length == 0) {
        accessType = "Public";
    } else if (Object.keys(diff(settings, teamSettings)).length == 0) {
        accessType = "Team";
    } else if (Object.keys(diff(settings, announcementOnlySettings)).length == 0) {
        accessType = "Announcement Only";
    } else if (Object.keys(diff(settings, restrictedSettings)).length == 0) {
        accessType = "Restricted";
    } else {
        accessType = "Custom";
    }
    return accessType;
}

/** Returns an object containing the key and value pairs for each difference between two objects
  * obj1: object you are comparing to default
  * obj2: default object
 */
function diff(obj1, obj2) {
    var diffs = {};
    for (key in obj2) {
        if (obj2.hasOwnProperty(key)) {
            if (obj1[key] !== obj2[key]) {
                diffs[key] = obj1[key];
            }
        }
    }
    return diffs;
}

/** Function called when user clicks to view access and membership settings */
function viewSettings() {
    hideElements(["view-settings-link"])
    showElements(["group-settings-chart", "hide-settings-link"])
}

/** Function called when user clicks to view access and membership settings */
function hideSettings() {
    showElements(["view-settings-link"])
    hideElements(["group-settings-chart", "hide-settings-link"])
}

/** Fills in the checkbox table for access and membership settings */
function setAccessMembershipSettingsTable(accessSettingsJson) {
    setAllCheckBoxesFalse(); // assume that all check box values should be overriden
    setCheckBoxesTrue(whoCanContactOwnerCheckboxMap[accessSettingsJson.whoCanContactOwner]);
    setCheckBoxesTrue(whoCanViewMembershipCheckboxMap[accessSettingsJson.whoCanViewMembership]);
    setCheckBoxesTrue(whoCanViewGroupCheckboxMap[accessSettingsJson.whoCanViewGroup]);
    setCheckBoxesTrue(whoCanPostMessageCheckboxMap[accessSettingsJson.whoCanPostMessage]);
    setCheckBoxesTrue(whoCanModifyMembersCheckboxMap[accessSettingsJson.whoCanModifyMembers]);
}

/** sets all check boxes for groups settings to false */
function setAllCheckBoxesFalse() {
    for (checkBox of document.getElementsByClassName("table-checkbox-input")) {
        checkBox.checked = false;
    }
}

/** sets check boxes true */
function setCheckBoxesTrue(checkBoxes) {
    for (checkBoxId of checkBoxes) {
        document.getElementById(checkBoxId).checked = true;
    }
}

/** Shows the edit fields for the information section */
function showEditInformationForm() {
    hideElements(["view-information-form", "show-edit-information-form"]);
    showElements(["edit-information-form", "save-information-form", "close-edit-information-form"]);

    document.getElementById("group-name-field").value = group.name;
    document.getElementById("group-email-field").value = group.email.split("@")[0];
    document.getElementById("group-email-domain").innerHTML = "@" + domain;

    var groupDescription = document.getElementById("group-description-field");
    if (group.description) groupDescription.value = group.description;
}

/** Saves the edit fields for the information section */
async function saveInformationForm() {
    isLoading = true;
    setLoadingOverlay();

    var groupName = document.getElementById("group-name-field").value;
    var groupEmail = document.getElementById("group-email-field").value;
    var groupDescription = document.getElementById("group-description-field").value;

    const response = await fetch('https://www.googleapis.com/admin/directory/v1/groups/'
    + group.id, {
        headers: {
            'authorization': `Bearer ` + token,
            'Content-Type': 'application/json'
        },
        method: 'PUT',
        body: JSON.stringify({"name": groupName, "email": groupEmail + "@" + domain, "description": groupDescription})
    })
    const groupJson = await response.json();
    console.log(groupJson)

    if (response.status == 200) {
        group = groupJson;
        setGroupInformation();
        closeInformationForm();
        isLoading = false;
        setLoadingOverlay();
    }
}

/** Hides the edit fields for the information section without saving */
function closeInformationForm() {
    showElements(["view-information-form", "show-edit-information-form"]);
    hideElements(["edit-information-form", "save-information-form", "close-edit-information-form"]);
}

/** Shows the edit fields for the settings section */
function showEditSettingsForm() {
    hideElements(["show-edit-settings-form", "access-type", "join-group", "members-outside-org"]);
    showElements(["save-settings-form", "close-edit-settings-form", "access-type-radio-group", "join-group-sel-group", "members-outside-org-switch-group", "save-settings-label"]);

    // Set values based on current group settings
    document.getElementById("access-type-radio-" + accessType.replace(/ /g, '-').toLowerCase()).checked = true;
    document.getElementById("join-group-sel").value = settings.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "anyone-can-join" : settings.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "anyone-can-ask" : "only-invited";
    document.getElementById("members-outside-org-switch").checked = settings.allowExternalMembers == "true" ? true : false;
}

/** Saves the edit fields for the settings section */
async function saveSettingsForm() {
    isLoading = true;
    setLoadingOverlay();

    var newPartialSettings = selectAccessType();
    var newSettings = Object.assign(settings, newPartialSettings);

    const response = await fetch('https://www.googleapis.com/groups/v1/groups/'
    + group.email, {
        headers: {
            'authorization': `Bearer ` + token,
            'Content-Type': 'application/json'
        },
        method: 'PUT',
        body: JSON.stringify(newSettings)
    })
    const accessSettingsJson = await response.json();
    console.log(accessSettingsJson)

    if (response.status == 200) {
        settings = accessSettingsJson;
        setGroupSettings();
        closeSettingsForm();
        isLoading = false;
        setLoadingOverlay();
    }
}

/** Hides the edit fields for the settings section without saving */
function closeSettingsForm() {
    showElements(["show-edit-settings-form", "access-type", "join-group", "members-outside-org"]);
    hideElements(["save-settings-form", "close-edit-settings-form", "access-type-radio-group", "join-group-sel-group", "members-outside-org-switch-group", "save-settings-label"]);

    // Reset checkboxes to original settings
    setAccessMembershipSettingsTable(settings);
}

/** Function called when user selects a new access type */
function selectAccessType() {
    var accessTypeSelected = document.querySelector('input[name="access-type-radio"]:checked').value;
    // Select all the checkboxes that correspond to this access type
    var newSettings;
    if (accessTypeSelected == "public") {
        newSettings = publicSettings;
    } else if (accessTypeSelected == "team") {
        newSettings = teamSettings;
    } else if (accessTypeSelected == "announcement-only") {
        newSettings = announcementOnlySettings;
    } else if (accessTypeSelected == "restricted") {
        newSettings = restrictedSettings;
    } else {
        return;
    }

    document.getElementById("join-group-sel").value = newSettings.whoCanJoin == "ALL_IN_DOMAIN_CAN_JOIN" ? "anyone-can-join" : newSettings.whoCanJoin == "CAN_REQUEST_TO_JOIN" ? "anyone-can-ask" : "only-invited";
    document.getElementById("members-outside-org-switch").checked = newSettings.allowExternalMembers == "true" ? true : false;

    setAccessMembershipSettingsTable(newSettings);
    return newSettings;
}

/** Deletes the current group */
async function deleteGroup() {
    isLoading = true;
    setLoadingOverlay();

    const response = await fetch('https://www.googleapis.com/admin/directory/v1/groups/'
    + group.id, {
        headers: {
            'authorization': `Bearer ` + token
        },
        method: 'DELETE',
    })
    if (response.status == 200 || response.status == 204) {
        isLoading = false;
        setLoadingOverlay();
        window.location.href = "groups.html";
    }
}

/** Double checks that the user wants to delete this group */
function deleteGroupModal() {
    $('#deleteModal').modal('show');
}<|endoftext|>