<commit_before>import React from 'react'
import styled, { css } from 'styled-components'
import {
  Flex,
  Box,
  Heading,
  Text,
  Link as A,
  Container,
  hexa,
  theme
} from '@hackclub/design-system'
import Icon from '@hackclub/icons'
import Link from 'gatsby-link'

const Base = styled(Box.withComponent('footer'))`
  background: ${props =>
    props.dark
      ? `${theme.colors.darker} radial-gradient(${hexa(
          theme.colors.black,
          0.5
        )} 1px, transparent 1px)`
      : `${theme.colors.snow} url('/pattern.svg') repeat`};
  ${props =>
    props.dark &&
    css`
      background-size: ${theme.space[4]}px ${theme.space[4]}px;
      h2 {
        color: ${theme.colors.gray[4]};
      }
      ${BottomLine} {
        border-color: ${theme.colors.black};
      }
    `} @media print {
    display: none;
  }
`

const Columns = styled(Container)`
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: ${theme.space[2]}px;

  ${theme.mediaQueries.md} {
    grid-gap: ${theme.space[4]}px;
    grid-template-columns: repeat(4, 1fr);
  }
`
const SocialColumn = styled(Box)``

const Services = styled(Flex)`
  a {
    line-height: 0;
  }
  svg {
    fill: currentColor;
    width: 32px;
    height: 32px;
  }
  ${theme.mediaQueries.md} {
    max-width: 12rem;
  }
`
Services.defaultProps = {
  align: 'center',
  mb: 3,
  wrap: true
}

const Service = ({ href, icon, ...props }) => (
  <A
    target="_blank"
    rel="noopener"
    href={href}
    mr={2}
    mb={2}
    color="muted"
    aria-label={`hack club on ${icon}`}
    children={<Icon glyph={icon} />}
    {...props}
  />
)

const Pages = styled(Box)`
  a {
    display: block;
    color: inherit;
    margin-bottom: ${theme.space[2]}px;
  }
`

const BottomLine = styled(Box)`
  border-top: 1px solid ${theme.colors.smoke};
`

const Footer = ({ dark = false, children, ...props }) => (
  <Base
    color={dark ? 'muted' : 'slate'}
    py={[4, 5]}
    dark={dark}
    align="left"
    {...props}
  >
    {children}
    <Columns px={3}>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Hack Club
        </Heading.h2>
        <Pages>
          {/* <Link to="/" children="Home" /> */}
          <Link to="/donate" children="Donate" />
          <Link to="/team" children="Team" />
          <Link to="/updates" children="Updates" />
          <Link to="/hackers" children="Hackers" />
          <Link to="/philosophy" children="Philosophy" />
        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          For Clubs
        </Heading.h2>
        <Pages>
          <Link to="/start" children="Start" />
          <Link to="/apply" children="Apply" />
          <Link to="/challenge" children="Challenge" />
          <Link to="/workshops" children="Workshops" />

        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Resources
        </Heading.h2>
        <Pages>

          <Link to="/bank" children="Bank" />
          <Link to="/night" children="Hack Night" />
        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Join the Club
        </Heading.h2>
        <Services>
          <Service href="/slack_invite" icon="slack" />
          <Service href="https://twitter.com/hackclub" icon="twitter" />
          <Service href="https://github.com/hackclub" icon="github" />
          <Service
            href="https://www.facebook.com/Hack-Club-741805665870458"
            icon="facebook"
          />
          <Service href="https://medium.com/hackclub" icon="medium" />
          <Service
            href="https://www.youtube.com/channel/UCQzO0jpcRkP-9eWKMpJyB0w"
            icon="youtube"
          />
          <Service
            href="https://www.instagram.com/starthackclub"
            icon="instagram"
          />
          <Service href="mailto:team@hackclub.com" icon="email" />
        </Services>
        <Text my={2}>
          1-855-625-HACK

          <Text.span color="muted" children="(call toll-free)" />
        </Text>
      </Box>
    </Columns>
    <Container px={3} mt={[3, 4]}>
      <Box f={2}>
        <Text>Office: 576 Natoma St, San Francisco, CA 94103</Text>
        <Text>Mail: 8605 Santa Monica Blvd #86294, Los Angeles, CA 90069</Text>
      </Box>
      <BottomLine mt={3}>
        <Text f={1} mt={2} color="muted">
          © {new Date().getFullYear()} Hack Club. Nonprofit EIN: 81-2908499.
        </Text>
      </BottomLine>
    </Container>
  </Base>
)

export default Footer
<commit_msg>Add Finder to footer<commit_after>import React from 'react'
import styled, { css } from 'styled-components'
import {
  Flex,
  Box,
  Heading,
  Text,
  Link as A,
  Container,
  hexa,
  theme
} from '@hackclub/design-system'
import Icon from '@hackclub/icons'
import Link from 'gatsby-link'

const Base = styled(Box.withComponent('footer'))`
  background: ${props =>
    props.dark
      ? `${theme.colors.darker} radial-gradient(${hexa(
          theme.colors.black,
          0.5
        )} 1px, transparent 1px)`
      : `${theme.colors.snow} url('/pattern.svg') repeat`};
  ${props =>
    props.dark &&
    css`
      background-size: ${theme.space[4]}px ${theme.space[4]}px;
      h2 {
        color: ${theme.colors.gray[4]};
      }
      ${BottomLine} {
        border-color: ${theme.colors.black};
      }
    `} @media print {
    display: none;
  }
`

const Columns = styled(Container)`
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: ${theme.space[2]}px;

  ${theme.mediaQueries.md} {
    grid-gap: ${theme.space[4]}px;
    grid-template-columns: repeat(4, 1fr);
  }
`
const SocialColumn = styled(Box)``

const Services = styled(Flex)`
  a {
    line-height: 0;
  }
  svg {
    fill: currentColor;
    width: 32px;
    height: 32px;
  }
  ${theme.mediaQueries.md} {
    max-width: 12rem;
  }
`
Services.defaultProps = {
  align: 'center',
  mb: 3,
  wrap: true
}

const Service = ({ href, icon, ...props }) => (
  <A
    target="_blank"
    rel="noopener"
    href={href}
    mr={2}
    mb={2}
    color="muted"
    aria-label={`hack club on ${icon}`}
    children={<Icon glyph={icon} />}
    {...props}
  />
)

const Pages = styled(Box)`
  a {
    display: block;
    color: inherit;
    margin-bottom: ${theme.space[2]}px;
  }
`

const BottomLine = styled(Box)`
  border-top: 1px solid ${theme.colors.smoke};
`

const Footer = ({ dark = false, children, ...props }) => (
  <Base
    color={dark ? 'muted' : 'slate'}
    py={[4, 5]}
    dark={dark}
    align="left"
    {...props}
  >
    {children}
    <Columns px={3}>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Hack Club
        </Heading.h2>
        <Pages>
          {/* <Link to="/" children="Home" /> */}
          <Link to="/donate" children="Donate" />
          <Link to="/team" children="Team" />
          <Link to="/updates" children="Updates" />
          <Link to="/hackers" children="Hackers" />
          <Link to="/philosophy" children="Philosophy" />
        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          For Clubs
        </Heading.h2>
        <Pages>
          <Link to="/start" children="Start" />
          <Link to="/apply" children="Apply" />
          <Link to="/challenge" children="Challenge" />
          <Link to="/workshops" children="Workshops" />

        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Resources
        </Heading.h2>
        <Pages>

          <Link to="/bank" children="Bank" />
          <Link to="/night" children="Hack Night" />
        </Pages>
      </Box>
      <Box>
        <Heading.h2 f={3} mb={3}>
          Join the Club
        </Heading.h2>
        <Services>
          <Service href="/slack_invite" icon="slack" />
          <Service href="https://twitter.com/hackclub" icon="twitter" />
          <Service href="https://github.com/hackclub" icon="github" />
          <Service
            href="https://www.facebook.com/Hack-Club-741805665870458"
            icon="facebook"
          />
          <Service href="https://medium.com/hackclub" icon="medium" />
          <Service
            href="https://www.youtube.com/channel/UCQzO0jpcRkP-9eWKMpJyB0w"
            icon="youtube"
          />
          <Service
            href="https://www.instagram.com/starthackclub"
            icon="instagram"
          />
          <Service href="mailto:team@hackclub.com" icon="email" />
        </Services>
        <Text my={2}>
          1-855-625-HACK

          <Text.span color="muted" children="(call toll-free)" />
        </Text>
      </Box>
    </Columns>
    <Container px={3} mt={[3, 4]}>
      <Box f={2}>
        <Text>Office: 576 Natoma St, San Francisco, CA 94103</Text>
        <Text>Mail: 8605 Santa Monica Blvd #86294, Los Angeles, CA 90069</Text>
      </Box>
      <BottomLine mt={3}>
        <Text f={1} mt={2} color="muted">
          © {new Date().getFullYear()} Hack Club. Nonprofit EIN: 81-2908499.
        </Text>
      </BottomLine>
    </Container>
  </Base>
)

export default Footer
<|endoftext|>


<commit_before>import React from "react";
import moment from "moment";

import ContentWrapper from "./ContentWrapper";
// import SignUpForm from "./SignUpForm.js";

import mail from "../assets/img/icons/socialMail.svg";
import twitter from "../assets/img/icons/socialTwitter.svg";
import logo from "../assets/img/logo/qhacksCrown-white.svg";
import facebook from "../assets/img/icons/socialFacebook.svg";
import instagram from "../assets/img/icons/socialInstagram.svg";
import wordmark from "../assets/img/logo/qhacksWordmark-white.svg";
import MediaQuery from "react-responsive";

const navigateLinks = [
  {
    label: "QHacks 2019",
    url: "https://2019.qhacks.io/",
    dataCy: "footer-2018-link"
  },
  {
    label: "Local Hack Day",
    url: "https://localhackday.mlh.io/",
    dataCy: "footer-lhd-link"
  },
  {
    label: "QHacks Blog",
    url: "https://medium.com/@qhacks",
    dataCy: "footer-blog-link"
  },
  // {
  //   label: "QHacks Dashboard",
  //   url: "https://app.qhacks.io",
  //   dataCy: "footer-dashboard-link"
  // },
  {
    label: "MLH Code of Conduct",
    url: "https://static.mlh.io/docs/mlh-code-of-conduct.pdf",
    dataCy: "footer-mlh-code-of-conduct-link"
  }
];

const socialLinks = [
  {
    icon: mail,
    url: "mailto:hello@qhacks.io",
    label: "hello@qhacks.io",
    dataCy: "footer-email-link"
  },
  {
    icon: twitter,
    url: "https://twitter.com/qhacks2020",
    label: "Follow us on Twitter",
    dataCy: "footer-twitter-link"
  },
  {
    icon: facebook,
    url: "https://fb.com/qhacks",
    label: "Like us on Facebook",
    dataCy: "footer-facebook-link"
  },
  {
    icon: instagram,
    url: "https://www.instagram.com/q_hacks/",
    label: "Follow us on Instagram",
    dataCy: "footer-instagram-link"
  }
];

const finePrint = {
  color: "#bebebe",
  fontSize: "12px"
};

const [smallScreens, mediumScreens, largeScreens] = [
  "@media(max-width: 950px)",
  "@media (min-width: 950px) and (max-width: 1200px)",
  "@media(min-width: 1200px)"
];

const Footer = () => (

    <ContentWrapper>

            QHacks is Queen’s University’s annual hackathon! QHacks was founded
            in 2016 with a mission to advocate and incubate the tech community
            at Queen’s University and throughout Canada. Going into our fifth
            year, we have been aggressively growing to become one of the biggest
            and most exciting hackathons in North America.

          {/*
Stay Connected
 */}
          {/*

            Sign up for our mailing list for the latest updates.

 */}

            <MediaQuery query="screen and (max-width: 950px)">
              {/* <SignUpForm
                fontSize={14}
                backgroundColor="#c81c2e"
                foregroundColor="white"
                dataCy="footer-signup-button"
                center={true}
              /> */}
            </MediaQuery>
            <MediaQuery query="screen and (min-width: 950px)">
              {/* <SignUpForm
                fontSize={14}
                backgroundColor="#c81c2e"
                foregroundColor="white"
                dataCy="footer-signup-button"
              /> */}
            </MediaQuery>

              Queen's University | 99 University Ave, Kingston, ON

              {"< />"} with ♡ by Queen's students

              Copyright © {moment().year()} QHacks

Navigate

li": { paddingBottom: "23px" },
              " a": {
                zIndex: "9999",
                color: "inherit",
                fontWeight: 600,
                textDecoration: "none",
                ":hover": {
                  color: "#ed253a"
                },
                [smallScreens]: {zIndex: "9999"}
              }
            }}
          >
            {navigateLinks.map(({ label, url, dataCy }) => (

                {`${label} ▸`}

            ))}

Get in touch

div": { paddingBottom: "18px" },
              " a": {
                textDecoration: "none",
                textAlign: "left",
                color: "inherit",
                fontWeight: "bold"
              },
              display: "grid",
              [smallScreens]: {
                marginLeft: "auto",
                marginRight: "auto",
                gridTemplateColumns: "1fr 1fr 1fr 1fr",
                maxWidth: "196px",
                paddingTop: "0px",
                paddingBottom: "60px"
              }
            }}
          >
            {socialLinks.map(({ icon, label, url, dataCy }) => (

div": {
                        backgroundColor: "#ed253a"
                      }
                    }
                  },
                  [smallScreens]: {
                    zIndex: "9999",
                    display: "block",
                    width: "40px",
                    height: "40px",
                    marginLeft: "auto",
                    marginRight: "auto"
                  }
                }}
              >

                  <div
                    css={{
                      backgroundColor: "#e3e3e3",
                      mask: `url(${icon}) no-repeat center center`,
                      maskSize: "100% 100%",
                      width: "28px",
                      height: "28px",
                      marginRight: "16px",
                      marginTop: "-5px",
                      ":hover": {
                        backgroundColor: "#ed253a"
                      },
                      [smallScreens]: {
                        zIndex: "9999",
                        width: "40px",
                        height: "40px"
                      }
                    }}
                  />

                  {label}

            ))}

            Queen's University | 99 University Ave, Kingston, ON

            {"< />"} with ♡ by Queen's students

            Copyright © {moment().year()} QHacks

    </ContentWrapper>

);

export default Footer;
<commit_msg>fixed footer/mobile menu overlap<commit_after>import React from "react";
import moment from "moment";

import ContentWrapper from "./ContentWrapper";
// import SignUpForm from "./SignUpForm.js";

import mail from "../assets/img/icons/socialMail.svg";
import twitter from "../assets/img/icons/socialTwitter.svg";
import logo from "../assets/img/logo/qhacksCrown-white.svg";
import facebook from "../assets/img/icons/socialFacebook.svg";
import instagram from "../assets/img/icons/socialInstagram.svg";
import wordmark from "../assets/img/logo/qhacksWordmark-white.svg";
import MediaQuery from "react-responsive";

const navigateLinks = [
  {
    label: "QHacks 2019",
    url: "https://2019.qhacks.io/",
    dataCy: "footer-2018-link"
  },
  {
    label: "Local Hack Day",
    url: "https://localhackday.mlh.io/",
    dataCy: "footer-lhd-link"
  },
  {
    label: "QHacks Blog",
    url: "https://medium.com/@qhacks",
    dataCy: "footer-blog-link"
  },
  // {
  //   label: "QHacks Dashboard",
  //   url: "https://app.qhacks.io",
  //   dataCy: "footer-dashboard-link"
  // },
  {
    label: "MLH Code of Conduct",
    url: "https://static.mlh.io/docs/mlh-code-of-conduct.pdf",
    dataCy: "footer-mlh-code-of-conduct-link"
  }
];

const socialLinks = [
  {
    icon: mail,
    url: "mailto:hello@qhacks.io",
    label: "hello@qhacks.io",
    dataCy: "footer-email-link"
  },
  {
    icon: twitter,
    url: "https://twitter.com/qhacks2020",
    label: "Follow us on Twitter",
    dataCy: "footer-twitter-link"
  },
  {
    icon: facebook,
    url: "https://fb.com/qhacks",
    label: "Like us on Facebook",
    dataCy: "footer-facebook-link"
  },
  {
    icon: instagram,
    url: "https://www.instagram.com/q_hacks/",
    label: "Follow us on Instagram",
    dataCy: "footer-instagram-link"
  }
];

const finePrint = {
  color: "#bebebe",
  fontSize: "12px"
};

const [smallScreens, mediumScreens, largeScreens] = [
  "@media(max-width: 950px)",
  "@media (min-width: 950px) and (max-width: 1200px)",
  "@media(min-width: 1200px)"
];

const Footer = () => (

    <ContentWrapper>

            QHacks is Queen’s University’s annual hackathon! QHacks was founded
            in 2016 with a mission to advocate and incubate the tech community
            at Queen’s University and throughout Canada. Going into our fifth
            year, we have been aggressively growing to become one of the biggest
            and most exciting hackathons in North America.

          {/*
Stay Connected
 */}
          {/*

            Sign up for our mailing list for the latest updates.

 */}

            <MediaQuery query="screen and (max-width: 950px)">
              {/* <SignUpForm
                fontSize={14}
                backgroundColor="#c81c2e"
                foregroundColor="white"
                dataCy="footer-signup-button"
                center={true}
              /> */}
            </MediaQuery>
            <MediaQuery query="screen and (min-width: 950px)">
              {/* <SignUpForm
                fontSize={14}
                backgroundColor="#c81c2e"
                foregroundColor="white"
                dataCy="footer-signup-button"
              /> */}
            </MediaQuery>

              Queen's University | 99 University Ave, Kingston, ON

              {"< />"} with ♡ by Queen's students

              Copyright © {moment().year()} QHacks

Navigate

li": { paddingBottom: "23px" },
              " a": {
                zIndex: "9999",
                color: "inherit",
                fontWeight: 600,
                textDecoration: "none",
                ":hover": {
                  color: "#ed253a"
                },
                [smallScreens]: {zIndex: "9999"}
              }
            }}
          >
            {navigateLinks.map(({ label, url, dataCy }) => (

                {`${label} ▸`}

            ))}

Get in touch

div": { paddingBottom: "18px" },
              " a": {
                textDecoration: "none",
                textAlign: "left",
                color: "inherit",
                fontWeight: "bold"
              },
              display: "grid",
              [smallScreens]: {
                marginLeft: "auto",
                marginRight: "auto",
                gridTemplateColumns: "1fr 1fr 1fr 1fr",
                maxWidth: "196px",
                paddingTop: "0px",
                paddingBottom: "60px"
              }
            }}
          >
            {socialLinks.map(({ icon, label, url, dataCy }) => (

div": {
                        backgroundColor: "#ed253a"
                      }
                    }
                  },
                  [smallScreens]: {
                    zIndex: "9999",
                    display: "block",
                    width: "40px",
                    height: "40px",
                    marginLeft: "auto",
                    marginRight: "auto"
                  }
                }}
              >

                  <div
                    css={{
                      backgroundColor: "#e3e3e3",
                      mask: `url(${icon}) no-repeat center center`,
                      maskSize: "100% 100%",
                      width: "28px",
                      height: "28px",
                      marginRight: "16px",
                      marginTop: "-5px",
                      ":hover": {
                        backgroundColor: "#ed253a"
                      },
                      [smallScreens]: {
                        zIndex: "9999",
                        width: "40px",
                        height: "40px"
                      }
                    }}
                  />

                  {label}

            ))}

            Queen's University | 99 University Ave, Kingston, ON

            {"< />"} with ♡ by Queen's students

            Copyright © {moment().year()} QHacks

    </ContentWrapper>

);

export default Footer;
<|endoftext|>


<commit_before>/*global require:true*/
/*global console:true*/
/*global __dirname:true*/
(function( exports ){
	"use strict";

	var phantomJsPath = require("phantomjs-prebuilt").path;
	var execFile = require("child_process").execFile;
	var path = require( "path" );
	var fs = require( "fs" );
	var os = require( "os" );
	var postcss = require( "postcss" );
	var css = require('css');
	var _ = require("lodash");

	var DEFAULT_BUFFER_SIZE = 800*1024; //had this as the set val before, don't want to break things

	exports.getRules = function( cssfile, opts, cb ){
		var defaultCb = function( err, output ){
			if( err ){
				throw new Error( err );
			} else {
				console.log( output );
			}
		};

		if( typeof cssfile !== "string" ){
			throw new TypeError( "The CSS filename must be a string" );
		}

		if( !fs.existsSync( cssfile ) ){
			throw new Error( "CSS file must exist" );
		}

		if( typeof opts === "undefined" && typeof cb === "undefined" ){
			opts = {};
			cb = defaultCb;
		}

		if( typeof opts === "function" ){
			cb = opts;
			opts = {};
		}

		var bufferSize = opts.buffer || DEFAULT_BUFFER_SIZE;

		execFile( phantomJsPath,
			[
				path.resolve( path.join( __dirname, "lib", "rules.js" ) ),
				cssfile
			],
			{
				maxBuffer: bufferSize
			},

			function(err, stdout, stderr){
				if( err ){
					console.log("\nSomething went wrong with phantomjs...");
					if( stderr ){
						err.message = stderr;
					}
					cb( err, null );
				} else {
					stdout = stdout.replace("Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL ", "");
					stdout = stdout.replace(/file:\/\/.*rules.js\./, "");
					stdout = stdout.replace(" Domains, protocols and ports must match.\n\n", "");
					stdout = stdout.replace(" Domains, protocols and ports must match.\r\n\r\n", ""); //windows
					cb( null, stdout );
				}

			}
		);
	};

	exports.findCritical = function( url, opts, cb ){
		var defaultCb = function( err, output ){
			if( err ){
				throw new Error( err );
			} else {
				console.log( output );
			}
		};

		if( typeof url !== "string" ){
			throw new TypeError( "URL must be a string" );
		}

		if( typeof opts === "undefined" && typeof cb === "undefined" ){
			opts = {};
			cb = defaultCb;
		}

		if( typeof opts === "function" ){
			cb = opts;
			opts = {};
		}

		var width = opts.width || 1200;
		var height = opts.height || 900;
		var forceInclude = opts.forceInclude || [];
		var rules = opts.rules || [];
		var usepostcss = opts.postcss;
		var tmpfile;

		var bufferSize = opts.buffer || DEFAULT_BUFFER_SIZE;

		if( !Array.isArray( forceInclude ) ){
			throw new Error( "forceInclude must be an array of selectors" );
		}

		var rulesString = JSON.stringify( rules );

		//var MAX_ARG_STRLEN = 131072; // on unix machines, the longest string an argument can be
		tmpfile = path.join( os.tmpdir(), "criticalcss-findcritical-rules" + (new Date()).getTime() );
		try {
			fs.writeFileSync( tmpfile, rulesString );
		} catch( e ){
			throw e;
		}

		var execArgs = [
				path.resolve( path.join( __dirname, "lib", "criticalrunner.js" ) ),
				url,
				width,
				height,
				JSON.stringify( forceInclude ),
				tmpfile
		];

		if( opts.ignoreConsole ){
			execArgs.push( "--ignoreConsole" );
		}

		execFile( phantomJsPath,
						 execArgs,
			{
				maxBuffer: bufferSize
			},

			function(err, stdout, stderr){
				if( err ){
					console.log("\nSomething went wrong with phantomjs...");
					if( stderr ){
						err.message = stderr;
					}
					cb( err, null );
				} else {
					if( usepostcss ){
						postcss([ require('postcss-initial') ])
							.process(stdout)
							.then(function (result) {
								cb(null, result.css);
							});

						return;
					}

					cb( null, stdout );
				}

				if( fs.existsSync(tmpfile) ){
					fs.unlinkSync(tmpfile);
				}
			}
		);

	};

	// create a function that can be passed to `map` for a collection of critical
	// css rules. The function will match original rules against the selector of
	// the critical css declarations, concatenate them together, and then keep
	// only the unique ones
	function replaceDecls(originalRules, check){
		return function(criticalRule){
			// restrict the declaration mapping to a certain type of rule, e.g. 'rule'
			// or 'media'
			if(check && !check(criticalRule.type)){
				return criticalRule;
			}

			// find all the rules in the original CSS that have the same selectors and
			// then create an array of all the associated declarations. Note that this
			// works with mutiple duplicate selectors on the original CSS
			var originalDecls = _.flatten(
				originalRules
					.filter(function(rule){
						return _.isEqual(rule.selectors, criticalRule.selectors);
					})
					.map(function(rule){
						return rule.declarations;
					})
			);

			// take all the declarations that were found from the original CSS and use
			// them here, make sure that we de-dup any declarations from the original CSS
			criticalRule.declarations = _.uniqBy(originalDecls, function(decl){
				return decl.property + ":" + decl.value;
			});

			return criticalRule;
		};
	}

	exports.restoreOriginalDefs = function(originalCSS, criticalCSS, stringifyOpts){
		// parse both the original CSS and the critical CSS so we can deal with the
		// ASTs directly
		var originalAST = css.parse(originalCSS);
		var criticalAST = css.parse(criticalCSS);

		var newRules;
		newRules = criticalAST
			.stylesheet
			.rules
			// for all the top level rules that are in the criticalCSS AST replace them
			// with the original rule definitions from the original AST
			.map(replaceDecls(originalAST.stylesheet.rules, function(ruleType){
				// only deal with top level rules here
				return ruleType === "rule";
			}))
			// for all the rules that are in media queries match the same media
			// queries in the original and use the rules from there
			.map(function(criticalMedia){
				// handle media rules only here
				if( criticalMedia.type !== "media" ){
					return criticalMedia;
				}

				// find all the rules that apply for the current media query
				var originalMediaRules;

				// get all of the rules inside media queries that match the critical
				// media query media string
				originalMediaRules = _.flatten(
					originalAST
						.stylesheet
						.rules
						.filter(function(rule){
							return rule.media == criticalMedia.media;
						})
						.map(function(media){
							return media.rules;
						})
				);

				// replace the declarations in each of the rules for this media query
				// with the declarations in the original css for the same media query
				criticalMedia.rules = criticalMedia
					.rules
					.map(replaceDecls(originalMediaRules));

				return criticalMedia;
			});

		criticalAST.stylesheet.rules = newRules;

		// return the CSS as a string
		return css.stringify(criticalAST, stringifyOpts);
	};

}(typeof exports === "object" && exports || this));
<commit_msg>more comments<commit_after>/*global require:true*/
/*global console:true*/
/*global __dirname:true*/
(function( exports ){
	"use strict";

	var phantomJsPath = require("phantomjs-prebuilt").path;
	var execFile = require("child_process").execFile;
	var path = require( "path" );
	var fs = require( "fs" );
	var os = require( "os" );
	var postcss = require( "postcss" );
	var css = require('css');
	var _ = require("lodash");

	var DEFAULT_BUFFER_SIZE = 800*1024; //had this as the set val before, don't want to break things

	exports.getRules = function( cssfile, opts, cb ){
		var defaultCb = function( err, output ){
			if( err ){
				throw new Error( err );
			} else {
				console.log( output );
			}
		};

		if( typeof cssfile !== "string" ){
			throw new TypeError( "The CSS filename must be a string" );
		}

		if( !fs.existsSync( cssfile ) ){
			throw new Error( "CSS file must exist" );
		}

		if( typeof opts === "undefined" && typeof cb === "undefined" ){
			opts = {};
			cb = defaultCb;
		}

		if( typeof opts === "function" ){
			cb = opts;
			opts = {};
		}

		var bufferSize = opts.buffer || DEFAULT_BUFFER_SIZE;

		execFile( phantomJsPath,
			[
				path.resolve( path.join( __dirname, "lib", "rules.js" ) ),
				cssfile
			],
			{
				maxBuffer: bufferSize
			},

			function(err, stdout, stderr){
				if( err ){
					console.log("\nSomething went wrong with phantomjs...");
					if( stderr ){
						err.message = stderr;
					}
					cb( err, null );
				} else {
					stdout = stdout.replace("Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL ", "");
					stdout = stdout.replace(/file:\/\/.*rules.js\./, "");
					stdout = stdout.replace(" Domains, protocols and ports must match.\n\n", "");
					stdout = stdout.replace(" Domains, protocols and ports must match.\r\n\r\n", ""); //windows
					cb( null, stdout );
				}

			}
		);
	};

	exports.findCritical = function( url, opts, cb ){
		var defaultCb = function( err, output ){
			if( err ){
				throw new Error( err );
			} else {
				console.log( output );
			}
		};

		if( typeof url !== "string" ){
			throw new TypeError( "URL must be a string" );
		}

		if( typeof opts === "undefined" && typeof cb === "undefined" ){
			opts = {};
			cb = defaultCb;
		}

		if( typeof opts === "function" ){
			cb = opts;
			opts = {};
		}

		var width = opts.width || 1200;
		var height = opts.height || 900;
		var forceInclude = opts.forceInclude || [];
		var rules = opts.rules || [];
		var usepostcss = opts.postcss;
		var tmpfile;

		var bufferSize = opts.buffer || DEFAULT_BUFFER_SIZE;

		if( !Array.isArray( forceInclude ) ){
			throw new Error( "forceInclude must be an array of selectors" );
		}

		var rulesString = JSON.stringify( rules );

		//var MAX_ARG_STRLEN = 131072; // on unix machines, the longest string an argument can be
		tmpfile = path.join( os.tmpdir(), "criticalcss-findcritical-rules" + (new Date()).getTime() );
		try {
			fs.writeFileSync( tmpfile, rulesString );
		} catch( e ){
			throw e;
		}

		var execArgs = [
				path.resolve( path.join( __dirname, "lib", "criticalrunner.js" ) ),
				url,
				width,
				height,
				JSON.stringify( forceInclude ),
				tmpfile
		];

		if( opts.ignoreConsole ){
			execArgs.push( "--ignoreConsole" );
		}

		execFile( phantomJsPath,
						 execArgs,
			{
				maxBuffer: bufferSize
			},

			function(err, stdout, stderr){
				if( err ){
					console.log("\nSomething went wrong with phantomjs...");
					if( stderr ){
						err.message = stderr;
					}
					cb( err, null );
				} else {
					if( usepostcss ){
						postcss([ require('postcss-initial') ])
							.process(stdout)
							.then(function (result) {
								cb(null, result.css);
							});

						return;
					}

					cb( null, stdout );
				}

				if( fs.existsSync(tmpfile) ){
					fs.unlinkSync(tmpfile);
				}
			}
		);

	};

	// create a function that can be passed to `map` for a collection of critical
	// css rules. The function will match original rules against the selector of
	// the critical css declarations, concatenate them together, and then keep
	// only the unique ones
	function replaceDecls(originalRules, check){
		return function(criticalRule){
			// restrict the declaration mapping to a certain type of rule, e.g. 'rule'
			// or 'media'
			if(check && !check(criticalRule.type)){
				return criticalRule;
			}

			// find all the rules in the original CSS that have the same selectors and
			// then create an array of all the associated declarations. Note that this
			// works with mutiple duplicate selectors on the original CSS
			var originalDecls = _.flatten(
				originalRules
					.filter(function(rule){
						return _.isEqual(rule.selectors, criticalRule.selectors);
					})
					.map(function(rule){
						return rule.declarations;
					})
			);

			// take all the declarations that were found from the original CSS and use
			// them here, make sure that we de-dup any declarations from the original CSS
			criticalRule.declarations = _.uniqBy(originalDecls, function(decl){
				return decl.property + ":" + decl.value;
			});

			return criticalRule;
		};
	}

	exports.restoreOriginalDefs = function(originalCSS, criticalCSS, stringifyOpts){
		// parse both the original CSS and the critical CSS so we can deal with the
		// ASTs directly
		var originalAST = css.parse(originalCSS);
		var criticalAST = css.parse(criticalCSS);

		var newRules;

		// run two maps over the rules in the critical CSS
		//
		// 1. map the top level rules to rules where the declarations are replaced
		//    by the declarations from the same selectors in the original CSS
		// 2. map the media query rules to rules where the declarations are replaced
		//    by the declarations from the same selectors in the same media queries
		//    in the original CSS
		newRules = criticalAST
			.stylesheet
			.rules
			// for all the top level rules that are in the criticalCSS AST replace them
			// with the original rule definitions from the original AST
			.map(replaceDecls(originalAST.stylesheet.rules, function(ruleType){
				// only deal with top level rules here
				return ruleType === "rule";
			}))
			// for all the rules that are in media queries match the same media
			// queries in the original and use the rules from there
			.map(function(criticalMedia){
				// handle media rules only here
				if( criticalMedia.type !== "media" ){
					return criticalMedia;
				}

				// find all the rules that apply for the current media query
				var originalMediaRules;

				// get all of the rules inside media queries that match the critical
				// media query media string
				originalMediaRules = _.flatten(
					originalAST
						.stylesheet
						.rules
						.filter(function(rule){
							return rule.media == criticalMedia.media;
						})
						.map(function(media){
							return media.rules;
						})
				);

				// replace the declarations in each of the rules for this media query
				// with the declarations in the original css for the same media query
				criticalMedia.rules = criticalMedia
					.rules
					.map(replaceDecls(originalMediaRules));

				return criticalMedia;
			});

		criticalAST.stylesheet.rules = newRules;

		// return the CSS as a string
		return css.stringify(criticalAST, stringifyOpts);
	};

}(typeof exports === "object" && exports || this));
<|endoftext|>


<commit_before><commit_msg>Issue #1941. Allow external login and register pages<commit_after><|endoftext|>


<commit_before>/* Purpose: Export development and production webpack configuration objects */

'use strict'

// Load modules
let env = require('../env')
let alert = require('../lib/alert')
let found = require('../lib/found')
let fs = require('fs-extra')
let abs = require('path').resolve
let webpack = require('webpack')

// Empty cache folder
fs.emptyDirSync(abs(env.cache, 'build'))

// Create configuration
let createConfiguration = function (mode) {
  // Define mode
  if (mode === '') {
    if (mode !== 'development' && mode !== 'production') {
      alert('Webpack configuration needs "production" or "development" as parameter.', 'issue')
    }
  }

  // Define string with all pages (to use in main.js)
  var pageStr = ''
  if (found(env.app, 'pages')) {
    var pageFiles = fs.readdirSync(abs(env.app, 'pages'))
    for (var p = 0; p < pageFiles.length; p++) {
      if (pageFiles[p].substr(pageFiles[p].length - 4, 4) === '.vue') {
        pageFiles[p] = pageFiles[p].replace(/\\/g, '/')
        if (p > 0) {
          pageStr += ','
        }
        pageStr += pageFiles[p].substr(0, pageFiles[p].length - 4)
      }
    }
  }

  // Define loaders
  let ExtractTextPlugin = require('extract-text-webpack-plugin')
  let loaders = [
    // JS files
    {
      test: /\.js$/,
      loader: 'babel',
      include: [
        abs(__dirname, '../lib'),
        abs(__dirname, '../scripts'),
        abs(env.app, 'app')
      ]
    },
    // Vue files
    {
      test: /\.vue$/,
      loader: 'vue'
    },
    // JSON files
    {
      test: /\.json$/,
      loader: 'json'
    },
    // CSS files
    {
      test: /\.css$/,
      loader: mode === 'development' ? 'vue-style-loader!css-loader' : ExtractTextPlugin.extract('css-loader' + (env.cfg.buildSourcemaps === true ? '?sourceMap' : ''))
    },
    // Image files
    {
      test: /\.(png|jpe?g|gif)(\?.*)?$/,
      loader: 'url',
      query: {
        limit: 1,
        name: 'img/[name].[hash:7].[ext]'
      }
    },
    // Favicon
    {
      test: /favicon\.ico$/,
      loader: 'url',
      query: {
        limit: 1,
        name: '[name].[ext]'
      }
    },
    // Font files
    {
      test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
      loader: 'url',
      query: {
        limit: 1,
        name: 'fonts/[name].[hash:7].[ext]'
      }
    }
  ]

  // Start configuration object
  let config = {
    entry: {
      app: [abs(__dirname, '../lib/main.js')]
    },
    output: {
      path: mode === 'development' ? '/' : abs(env.cache, 'build/www'),
      filename: '[name].[hash:7].js'
    },
    resolve: {
      extensions: ['', '.js', '.vue', '.json'],
      alias: {
        'vue$': 'vue/dist/vue.common.js'
      }
    },
    module: {
      loaders: loaders
    },
    plugins: []
  }

  // Add environment variables
  config.plugins.push(
    new webpack.DefinePlugin({
      'process.env': {
        THEME: '"' + env.cfg.theme + '"',
        APP_ROOT_FROM_SCRIPTS: '"' + (env.installed ? '../../../app/' : '../app/') + '"',
        CACHE_ROOT_FROM_SCRIPTS: '"' + (env.installed ? '../../../node_modules/.app-framework-cache/' : '../node_modules/.app-framework-cache/') + '"',
        FRAMEWORK_VERSION: '"' + env.pkg.version + '"',
        FONT_FRAMEWORK7: '"' + env.cfg.loadIconFonts.framework7 + '"',
        FONT_MATERIAL: '"' + env.cfg.loadIconFonts.material + '"',
        FONT_ION: '"' + env.cfg.loadIconFonts.ion + '"',
        FONT_AWESOME: '"' + env.cfg.loadIconFonts.fontawesome + '"',
        RESET_LOCAL_STORAGE: '"' + env.cfg.resetLocalStorageOnVersionChange + '"',
        PAGES: '"' + pageStr + '"',
        NODE_ENV: '"' + mode + '"',
        DEV_BUILD: '"' + (env.arg.dev === true) + '"'
      }
    })
  )

  // Optimize ordering, reduce size
  config.plugins.push(new webpack.optimize.OccurrenceOrderPlugin())

  // Avoid exit with error in CLI
  if (mode === 'development') {
    config.plugins.push(new webpack.NoErrorsPlugin())
  }

  // Add hot file reload in development mode
  if (mode === 'development') {
    config.entry['app'].unshift(abs(__dirname, '../lib/dev-client.js'))
    config.plugins.push(new webpack.HotModuleReplacementPlugin())
  }

  // Extract CSS code to extra file
  if (mode === 'production') {
    config.plugins.push(
      new ExtractTextPlugin('[name].[hash:7].css')
    )
    config.vue = {
      loaders: {
        css: ExtractTextPlugin.extract('vue-style-loader', 'css-loader' + (env.cfg.buildSourcemaps === true ? '?sourceMap' : ''))
      }
    }
  }

  // Define icon tags for production
  let iconTags = ''
  if (mode === 'production') {
    iconTags = '<meta name="theme-color" content="' + env.cfg.iconBackgroundColor + '" />' +
               '<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />' +
               '<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />' +
               '<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />' +
               '<link rel="manifest" href="manifest.json" />'
  } else {
    iconTags = ''
  }

  // Plugin: HTML index file generation
  let HtmlPlugin = require('html-webpack-plugin')
  config.plugins.push(
    new HtmlPlugin({
      // filename: mode === 'development' ? 'index.html' : abs(env.proj, 'build/index.html'),
      filename: 'index.html',
      template: abs(__dirname, '../index.ejs'),
      title: env.cfg.title,
      iconTags: mode === 'development' ? '' : iconTags, // favicon.ico will be loaded by browser default from root directory
      manifest: mode === 'production' ? ' manifest="manifest.appcache"' : '',
      inject: true,
      minify: mode === 'production' ? {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      } : undefined
    })
  )

  // Add source maps
  if (mode === 'development') {
    config.devtool = '#eval-source-map'
  } else if (mode === 'production' && env.cfg.buildSourcemaps === true) {
    config.devtool = '#source-map'
  } else {
    config.devtool = undefined
  }

  // Add JS compression
  if (mode === 'production') {
    config.plugins.push(
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false
        }
      })
    )
  }

  // Add cache manifest
  if (mode === 'production') {
    let AppCachePlugin = require('appcache-webpack-plugin')
    config.plugins.push(
      new AppCachePlugin({
        cache: null,
        network: ['*'],
        fallback: null,
        settings: null,
        exclude: [/\.(js|css)\.map$/],
        output: 'manifest.appcache'
      })
    )
  }

  // Return object
  return config
}

// Export configuration
module.exports = {
  development: createConfiguration('development'),
  production: createConfiguration('production')
}
<commit_msg>path fix<commit_after>/* Purpose: Export development and production webpack configuration objects */

'use strict'

// Load modules
let env = require('../env')
let alert = require('../lib/alert')
let found = require('../lib/found')
let fs = require('fs-extra')
let path = require('path')
let abs = require('path').resolve
let webpack = require('webpack')

// Empty cache folder
fs.emptyDirSync(abs(env.cache, 'build'))

// Create configuration
let createConfiguration = function (mode) {
  // Define mode
  if (mode === '') {
    if (mode !== 'development' && mode !== 'production') {
      alert('Webpack configuration needs "production" or "development" as parameter.', 'issue')
    }
  }

  // Define string with all pages (to use in main.js)
  var pageStr = ''
  if (found(env.app, 'pages')) {
    var pageFiles = fs.readdirSync(abs(env.app, 'pages'))
    for (var p = 0; p < pageFiles.length; p++) {
      if (pageFiles[p].substr(pageFiles[p].length - 4, 4) === '.vue') {
        pageFiles[p] = pageFiles[p].replace(/\\/g, '/')
        if (p > 0) {
          pageStr += ','
        }
        pageStr += pageFiles[p].substr(0, pageFiles[p].length - 4)
      }
    }
  }

  // Define loaders
  let ExtractTextPlugin = require('extract-text-webpack-plugin')
  let loaders = [
    // JS files
    {
      test: /\.js$/,
      loader: 'babel',
      include: [
        abs(__dirname, '../lib'),
        abs(__dirname, '../scripts'),
        abs(env.app, 'app')
      ]
    },
    // Vue files
    {
      test: /\.vue$/,
      loader: 'vue'
    },
    // JSON files
    {
      test: /\.json$/,
      loader: 'json'
    },
    // CSS files
    {
      test: /\.css$/,
      loader: mode === 'development' ? 'vue-style-loader!css-loader' : ExtractTextPlugin.extract('css-loader' + (env.cfg.buildSourcemaps === true ? '?sourceMap' : ''))
    },
    // Image files
    {
      test: /\.(png|jpe?g|gif)(\?.*)?$/,
      loader: 'url',
      query: {
        limit: 1,
        name: 'img/[name].[hash:7].[ext]'
      }
    },
    // Favicon
    {
      test: /favicon\.ico$/,
      loader: 'url',
      query: {
        limit: 1,
        name: '[name].[ext]'
      }
    },
    // Font files
    {
      test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
      loader: 'url',
      query: {
        limit: 1,
        name: 'fonts/[name].[hash:7].[ext]'
      }
    }
  ]

  // Start configuration object
  let config = {
    entry: {
      app: [abs(__dirname, '../lib/main.js')]
    },
    output: {
      path: mode === 'development' ? abs(env.app) : abs(env.cache, 'build/www'),
      xpublicPath: mode === 'development' ? path.relative(env.proj, env.app) : path.join('/'),
      filename: '[name].[hash:7].js'
    },
    resolve: {
      extensions: ['', '.js', '.vue', '.json'],
      alias: {
        'vue$': 'vue/dist/vue.common.js'
      }
    },
    module: {
      loaders: loaders
    },
    plugins: []
  }

  // Add environment variables
  config.plugins.push(
    new webpack.DefinePlugin({
      'process.env': {
        THEME: '"' + env.cfg.theme + '"',
        APP_ROOT_FROM_SCRIPTS: '"' + (env.installed ? '../../../app/' : '../app/') + '"',
        CACHE_ROOT_FROM_SCRIPTS: '"' + (env.installed ? '../../../node_modules/.app-framework-cache/' : '../node_modules/.app-framework-cache/') + '"',
        FRAMEWORK_VERSION: '"' + env.pkg.version + '"',
        FONT_FRAMEWORK7: '"' + env.cfg.loadIconFonts.framework7 + '"',
        FONT_MATERIAL: '"' + env.cfg.loadIconFonts.material + '"',
        FONT_ION: '"' + env.cfg.loadIconFonts.ion + '"',
        FONT_AWESOME: '"' + env.cfg.loadIconFonts.fontawesome + '"',
        RESET_LOCAL_STORAGE: '"' + env.cfg.resetLocalStorageOnVersionChange + '"',
        PAGES: '"' + pageStr + '"',
        NODE_ENV: '"' + mode + '"',
        DEV_BUILD: '"' + (env.arg.dev === true) + '"'
      }
    })
  )

  // Optimize ordering, reduce size
  config.plugins.push(new webpack.optimize.OccurrenceOrderPlugin())

  // Avoid exit with error in CLI
  if (mode === 'development') {
    config.plugins.push(new webpack.NoErrorsPlugin())
  }

  // Add hot file reload in development mode
  if (mode === 'development') {
    config.entry['app'].unshift(abs(__dirname, '../lib/dev-client.js'))
    config.plugins.push(new webpack.HotModuleReplacementPlugin())
  }

  // Extract CSS code to extra file
  if (mode === 'production') {
    config.plugins.push(
      new ExtractTextPlugin('[name].[hash:7].css')
    )
    config.vue = {
      loaders: {
        css: ExtractTextPlugin.extract('vue-style-loader', 'css-loader' + (env.cfg.buildSourcemaps === true ? '?sourceMap' : ''))
      }
    }
  }

  // Define icon tags for production
  let iconTags = ''
  if (mode === 'production') {
    iconTags = '<meta name="theme-color" content="' + env.cfg.iconBackgroundColor + '" />' +
               '<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />' +
               '<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />' +
               '<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />' +
               '<link rel="manifest" href="manifest.json" />'
  } else {
    iconTags = ''
  }

  // Plugin: HTML index file generation
  let HtmlPlugin = require('html-webpack-plugin')
  config.plugins.push(
    new HtmlPlugin({
      // filename: mode === 'development' ? 'index.html' : abs(env.proj, 'build/index.html'),
      filename: 'index.html',
      template: abs(__dirname, '../index.ejs'),
      title: env.cfg.title,
      iconTags: mode === 'development' ? '' : iconTags, // favicon.ico will be loaded by browser default from root directory
      manifest: mode === 'production' ? ' manifest="manifest.appcache"' : '',
      inject: true,
      minify: mode === 'production' ? {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      } : undefined
    })
  )

  // Add source maps
  if (mode === 'development') {
    config.devtool = '#eval-source-map'
  } else if (mode === 'production' && env.cfg.buildSourcemaps === true) {
    config.devtool = '#source-map'
  } else {
    config.devtool = undefined
  }

  // Add JS compression
  if (mode === 'production') {
    config.plugins.push(
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false
        }
      })
    )
  }

  // Add cache manifest
  if (mode === 'production') {
    let AppCachePlugin = require('appcache-webpack-plugin')
    config.plugins.push(
      new AppCachePlugin({
        cache: null,
        network: ['*'],
        fallback: null,
        settings: null,
        exclude: [/\.(js|css)\.map$/],
        output: 'manifest.appcache'
      })
    )
  }

  // Return object
  return config
}

// Export configuration
module.exports = {
  development: createConfiguration('development'),
  production: createConfiguration('production')
}
<|endoftext|>


<commit_before>import webpack from 'webpack';

const webpackConfig = () => {
  let webpackEntries = {};
  for (let key in config.scripts.entry) {
    let value = config.scripts.entry[key];
    webpackEntries[path.join(config.paths.target.js, key)] = config.production ?
      value : [
        value,
        'webpack-hot-middleware/client?noInfo=true&reload=true'
      ];
  }

  let resolveExtensions = ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json'].concat(config.scripts.extensions);

  let configuration = {
    entry: webpackEntries,
    output: {
      path: path.join(__dirname, '..', '..', '..', config.tmp.base),
      publicPath: config.scripts.publicPath,
      filename: config.scripts.filename
        //chunkFilename: '[chunkhash].js'
    },
    module: {
      loaders: config.scripts.loaders
    },
    postcss: () => {
      return [
        require('precss')(),
        require('autoprefixer')({
          browsers: config.styles.autoprefixer
        })
      ];
    },
    resolve: {
      extensions: resolveExtensions,
      modulesDirectories: [
        'node_modules',
        'bower_components',
        config.source.css,
        config.source.js
      ],
      alias: config.scripts.alias
    },
    resolveLoader: {
      modulesDirectories: [
        path.join(__dirname, '..', 'node_modules'), // for npm2
        path.join(__dirname, '..', '..') // for npm3
      ]
    },
    plugins: [
      new webpack.ResolverPlugin(
        new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main'])
      )
    ]
  };

  if (config.production) {
    configuration.devtool = '#source-map';
    configuration.plugins = configuration.plugins.concat([
      new webpack.optimize.DedupePlugin()
      // use gulp-uglify
      // new webpack.optimize.UglifyJsPlugin({
      //   compress: {
      //     warnings: config.debug ? true : false
      //   }
      // })
    ]);
  } else {
    configuration.debug = true;
    // eval-source-map is faster for development
    configuration.devtool = '#eval-source-map';
    configuration.plugins = configuration.plugins.concat([
      // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
      new webpack.optimize.OccurenceOrderPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoErrorsPlugin()
    ]);
  }

  return configuration;
};

export default webpackConfig;
<commit_msg>update<commit_after>import webpack from 'webpack';

const webpackConfig = () => {
  let webpackEntries = {};
  for (let key in config.scripts.entry) {
    let value = config.scripts.entry[key];
    webpackEntries[path.join(config.paths.target.js, key)] = config.production ?
      value : [
        value,
        'webpack-hot-middleware/client?noInfo=true&reload=true'
      ];
  }

  let resolveExtensions = ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json'].concat(config.scripts.extensions);

  let configuration = {
    entry: webpackEntries,
    output: {
      path: path.join(__dirname, '..', '..', '..', config.tmp.base),
      publicPath: config.scripts.publicPath,
      filename: config.scripts.filename
        //chunkFilename: '[chunkhash].js'
    },
    module: {
      loaders: config.scripts.loaders
    },
    postcss: () => {
      return [
        require('precss')(),
        require('autoprefixer')({
          browsers: config.styles.autoprefixer
        })
      ];
    },
    resolve: {
      extensions: resolveExtensions,
      modulesDirectories: [
        'node_modules',
        'bower_components',
        config.source.css,
        config.source.js
      ],
      alias: config.scripts.alias
    },
    resolveLoader: {
      modulesDirectories: [
        path.join(__dirname, '..', 'node_modules'), // for npm2
        path.join(__dirname, '..', '..') // for npm3
      ]
    },
    plugins: [
      new webpack.ResolverPlugin(
        new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin('bower.json', ['main'])
      )
    ]
  };

  if (config.production) {
    configuration.devtool = '#source-map';
    configuration.plugins = configuration.plugins.concat([
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: JSON.stringify('production')
        }
      }),
      new webpack.optimize.DedupePlugin()
      // use gulp-uglify
      // new webpack.optimize.UglifyJsPlugin({
      //   compress: {
      //     warnings: config.debug ? true : false
      //   }
      // })
    ]);
  } else {
    configuration.debug = true;
    // eval-source-map is faster for development
    configuration.devtool = '#eval-source-map';
    configuration.plugins = configuration.plugins.concat([
      // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
      new webpack.optimize.OccurenceOrderPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoErrorsPlugin()
    ]);
  }

  return configuration;
};

export default webpackConfig;
<|endoftext|>


<commit_before>var React = require('react');

var NavBar = React.createClass({
  render: function () {
    return (

Home

RMT Forum

Github

About

    );
  }
});

module.exports = NavBar;
<commit_msg>Add links to navbar<commit_after>var React = require('react');

var NavBar = React.createClass({
  render: function () {
    return (

Home

RMT Forum

Github

About

    );
  }
});

module.exports = NavBar;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link, IndexLink } from 'react-router';
import { connect } from 'react-redux';
import '../styles/components/Navbar.scss';

const navParentItems = [
  { title: 'Projects', href: '/projects', id: 1 },
  { title: 'Experience', href: '/about', id: 2},
  { title: 'Contact', href: '/contact', id: 3},
];

// This needs updating whenever there is a change to navParentItems
const PROJECTS_NAV_ITEM_ID = 1;

const widthPercent = 100 / navParentItems.length;

const mapStateToProps = (state) => ({
   pathname: state.location.pathname
})

class Navbar extends React.Component {
  constructor(props) {
    super(props);
    this.toggleNavOffset = this.toggleNavOffset.bind(this);
    this.onClickToggleNav =this.onClickToggleNav.bind(this);
  }

  componentWillMount() {
    const pathname = this.props.location.pathname;
    // get nav item id and toggle nav offset
    const index = navParentItems.findIndex(item => {
      if (item.href === pathname) {
        return item;
      }
    });
    if (index === -1 && pathname.includes('projects')) {
      var item = navParentItems[0].id;
    } else {
      var item = navParentItems[index].id;
    }
    this.toggleNavOffset(item);
  }

  componentDidMount() {
    this.setState({
      navMbContainer: 'nav-mb-box-inactive',
      toggleMobileNav: false
    })
  }

   toggleNavOffset(itemId) {
    let  offset = widthPercent * itemId
    this.setState({
      navOffset: offset.toFixed(2)
    });
  }

  onClickToggleNav() {
    if (this.state.toggleMobileNav) {
      this.setState({
        navMbContainer: 'nav-mb-box-inactive',
        toggleMobileNav: false
      })
    } else {
      this.setState({
        navMbContainer: 'nav-mb-box-active',
        toggleMobileNav: true
      })
    }
  }

  iconInitials() {
    if (this.props.location.pathname !== '/') {
      return (
        <Link to='/'>

ZS

        </Link>
      )
    }
  }

  toggleNavItems() {
    return this.state.toggleMobileNav ? 'mb-active' : 'mb-inactive'
  }

  toggleBurger() {
    return this.state.toggleMobileNav ? 'hamburger-is-active' : ''
  }

  render() {
    const singleProjectActive = this.props.location.pathname.includes('projects');
    const { toggleMobileNav } = this.state;
    return (

        {this.iconInitials()}

            {
              navParentItems.map((item) => {
                return (
                  <Link to={item.href}
                      key={item.id}
                      activeClassName="active"
                      style={{ width: `${widthPercent}%`}}
                      className={(singleProjectActive && item.id === PROJECTS_NAV_ITEM_ID) && 'active-child'}
                      onClick={() => this.toggleNavOffset(item.id)}>{item.title}
                  </Link>
                )
              })
            }

            <div className="indicator"
                style={{
                  left: `calc(${this.state.navOffset}% - 95px)`
                }}>

 this.onClickToggleNav()} className={ toggleMobileNav ? 'overlay-active overlay' : 'overlay overlay-opacity'}>

 this.onClickToggleNav()} className={`hamburger ${this.toggleBurger()}`}>

          <div className={`nav-mb-box ${this.state.navMbContainer}`}>

            {
              navParentItems.map((item) => {
                return (
                  <Link to={item.href}
                      key={item.id}
                      activeClassName="mb-underline"
                      onClick={()=> this.onClickToggleNav()}
                      className={this.toggleNavItems()}>

{item.title}

                  </Link>
                )
              })
            }

    )
  }
}

export default connect(mapStateToProps, null)(Navbar)
<commit_msg>mobile overlay can't reopen itself<commit_after>import React, { Component } from 'react';
import { Link, IndexLink } from 'react-router';
import { connect } from 'react-redux';
import '../styles/components/Navbar.scss';

const navParentItems = [
  { title: 'Projects', href: '/projects', id: 1 },
  { title: 'Experience', href: '/about', id: 2},
  { title: 'Contact', href: '/contact', id: 3},
];

// This needs updating whenever there is a change to navParentItems
const PROJECTS_NAV_ITEM_ID = 1;

const widthPercent = 100 / navParentItems.length;

const mapStateToProps = (state) => ({
   pathname: state.location.pathname
})

class Navbar extends React.Component {
  constructor(props) {
    super(props);
    this.toggleNavOffset = this.toggleNavOffset.bind(this);
    this.onClickToggleNav =this.onClickToggleNav.bind(this);
  }

  componentWillMount() {
    const pathname = this.props.location.pathname;
    // get nav item id and toggle nav offset
    const index = navParentItems.findIndex(item => {
      if (item.href === pathname) {
        return item;
      }
    });
    if (index === -1 && pathname.includes('projects')) {
      var item = navParentItems[0].id;
    } else {
      var item = navParentItems[index].id;
    }
    this.toggleNavOffset(item);
  }

  componentDidMount() {
    this.setState({
      navMbContainer: 'nav-mb-box-inactive',
      toggleMobileNav: false
    })
  }

   toggleNavOffset(itemId) {
    let  offset = widthPercent * itemId
    this.setState({
      navOffset: offset.toFixed(2)
    });
  }

  onClickToggleNav(overlay) {
    if (this.state.toggleMobileNav && !overlay) {
      this.setState({
        navMbContainer: 'nav-mb-box-inactive',
        toggleMobileNav: false
      })
    } else if(!this.state.toggleMobileNav && !overlay) {
      this.setState({
        navMbContainer: 'nav-mb-box-active',
        toggleMobileNav: true
      })
    } else {
      this.setState({
        navMbContainer: 'nav-mb-box-inactive',
        toggleMobileNav: false
      })
    }
  }

  iconInitials() {
    if (this.props.location.pathname !== '/') {
      return (
        <Link to='/'>

ZS

        </Link>
      )
    }
  }

  toggleNavItems() {
    return this.state.toggleMobileNav ? 'mb-active' : 'mb-inactive'
  }

  toggleBurger() {
    return this.state.toggleMobileNav ? 'hamburger-is-active' : ''
  }

  render() {
    const singleProjectActive = this.props.location.pathname.includes('projects');
    const { toggleMobileNav } = this.state;
    return (

        {this.iconInitials()}

            {
              navParentItems.map((item) => {
                return (
                  <Link to={item.href}
                      key={item.id}
                      activeClassName="active"
                      style={{ width: `${widthPercent}%`}}
                      className={(singleProjectActive && item.id === PROJECTS_NAV_ITEM_ID) && 'active-child'}
                      onClick={() => this.toggleNavOffset(item.id)}>{item.title}
                  </Link>
                )
              })
            }

            <div className="indicator"
                style={{
                  left: `calc(${this.state.navOffset}% - 95px)`
                }}>

 this.onClickToggleNav(true)} className={ toggleMobileNav ? 'overlay-active overlay' : 'overlay overlay-opacity'}>

 this.onClickToggleNav()} className={`hamburger ${this.toggleBurger()}`}>

          <div className={`nav-mb-box ${this.state.navMbContainer}`}>

            {
              navParentItems.map((item) => {
                return (
                  <Link to={item.href}
                      key={item.id}
                      activeClassName="mb-underline"
                      onClick={()=> this.onClickToggleNav()}
                      className={this.toggleNavItems()}>

{item.title}

                  </Link>
                )
              })
            }

    )
  }
}

export default connect(mapStateToProps, null)(Navbar)
<|endoftext|>


<commit_before>/*
 * syslog.js: Transport for logging to a remote syslog consumer
 *
 * (C) 2011 Squeeks and Charlie Robbins
 * MIT LICENCE
 *
 */

var dgram = require('dgram'),
    net = require('net'),
    util = require('util'),
    cycle = require('cycle'),
    glossy = require('glossy'),
    winston = require('winston'),
    common = require('winston/lib/winston/common');

var levels = Object.keys({
  debug: 0,
  info: 1,
  notice: 2,
  warning: 3,
  error: 4,
  crit: 5,
  alert: 6,
  emerg: 7
});

//
// ### function Syslog (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Syslog Transport capable of sending
// RFC 3164 and RFC 5424 compliant messages.
//
var Syslog = exports.Syslog = function (options) {
  winston.Transport.call(this, options);
  options = options || {};
  // Set transport name
  this.name = 'syslog';
  //
  // Setup connection state
  //
  this.connected = false;
  this.congested = false;
  this.retries = 0;
  this.queue = [];
  this.inFlight = 0;

  this.json        = options.json        || false;
  this.colorize    = options.colorize    || false;
  this.prettyPrint = options.prettyPrint || false;
  this.timestamp   = typeof options.timestamp !== 'undefined' ? options.timestamp : false;
  this.showLevel   = options.showLevel === undefined ? true : options.showLevel;
  this.label       = options.label       || null;
  this.logstash    = options.logstash    || false;
  this.depth       = options.depth       || null;

  //
  // Merge the options for the target Syslog server.
  //
  this.host     = options.host     || 'localhost';
  this.port     = options.port     || 514;
  this.path     = options.path     || null;
  this.appId    = options.appId    || options.app_id || null;
  this.protocol = options.protocol || 'udp4';
  this.isDgram  = /^udp|^unix/.test(this.protocol);
  this.endOfLine = options.eol;

  if (!/^udp|unix|unix-connect|tcp/.test(this.protocol)) {
    throw new Error('Invalid syslog protocol: ' + this.protocol);
  }

  if (/^unix/.test(this.protocol) && !this.path) {
    throw new Error('`options.path` is required on unix dgram sockets.');
  }

  //
  // Merge the default message options.
  //
  this.localhost = options.localhost || 'localhost';
  this.type      = options.type      || 'BSD';
  this.facility  = options.facility  || 'local0';
  this.pid       = options.pid       || process.pid;
  this.appName   = options.appName   || options.app_name  || process.title;

  //
  // Setup our Syslog and network members for later use.
  //
  this.socket   = null;
  this.producer = new glossy.Produce({
    type:     this.type,
    appName:  this.appName,
    pid:      this.pid,
    facility: this.facility
  });
};

//
// Inherit from `winston.Transport`.
//
util.inherits(Syslog, winston.Transport);

//
// Define a getter so that `winston.transports.Syslog`
// is available and thus backwards compatible.
//
winston.transports.Syslog = Syslog;

//
// Expose the name of this Transport on the prototype
//
Syslog.prototype.name = 'Syslog';
//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Target level to log to
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to log.
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Logs the `msg` and optional
// metadata, `meta`, to the specified `level`.
//
Syslog.prototype.log = function (level, msg, meta, callback) {
  var self = this,
      syslogMsg,
      buffer;

  if (!~levels.indexOf(level)) {
    return callback(new Error('Cannot log unknown syslog level: ' + level));
  }

  var output = common.log({
    colorize:    this.colorize,
    json:        this.json,
    level:       level,
    message:     msg,
    meta:        meta,
    stringify:   this.stringify,
    timestamp:   this.timestamp,
    showLevel:   this.showLevel,
    prettyPrint: this.prettyPrint,
    raw:         this.raw,
    label:       this.label,
    logstash:    this.logstash,
    depth:       this.depth,
    formatter:   this.formatter,
    humanReadableUnhandledException: this.humanReadableUnhandledException
  });

  syslogMsg = this.producer.produce({
    severity: level,
    host:     this.localhost,
    app_id:   this.appId || process.title,
    date:     new Date(),
    message:  this.endOfLine ? output + this.endOfLine : output
  });

  //
  // Attempt to connect to the socket
  //
  this.connect(function (err) {
    if (err) {
      //
      // If there was an error enqueue the message
      //
      self.queue.push(syslogMsg);

      return callback(err);
    }

    //
    // On any error writing to the socket, enqueue the message
    //
    function onError(logErr) {
      if (logErr) { self.queue.push(syslogMsg) }
      self.emit('logged');
      self.inFlight--;
    }

    function onCongestion() {
      onError(new Error('Congestion Error'));
    }

    //
    // Write to the `tcp*`, `udp*`, or `unix` socket.
    //
    if (self.isDgram) {
      buffer = new Buffer(syslogMsg);

      if (self.protocol.match(/^udp/)) {
        self.inFlight++;
        self.socket.send(buffer, 0, buffer.length, self.port, self.host, onError);
      }
      else if (self.protocol === 'unix') {
        self.socket.send(buffer, 0, buffer.length, self.path, onError);
      }
      else {
        if (self.congested) {
          self.queue.push(syslogMsg);
        }
        else {
          self.socket.once('congestion', onCongestion);
          self.socket.once('error', onError);
          self.socket.send(buffer, function () {
            self.socket.removeListener('congestion', onCongestion);
            self.socket.removeListener('error', onError);
            onError();
          });
        }
      }
    }
    else {
      self.socket.write(syslogMsg, 'utf8', onError);
    }

    callback(null, true);
  });
};
//
// ### function close ()
// Closes the socket used by this transport freeing the resource.
//
Syslog.prototype.close = function () {
  var self = this,
      max = 6,
      attempt = 0;

  (function _close() {
    if (attempt >= max || (self.queue.length === 0 && self.inFlight <= 0)) {
      if (self.socket) {
        self.socket.close();
      }

      self.emit('closed', self.socket);
    }
    else {
      attempt++;
      setTimeout(_close, 200 * attempt);
    }
  }());
};

//
// ### function connect (callback)
// #### @callback {function} Continuation to respond to when complete.
// Connects to the remote syslog server using `dgram` or `net` depending
// on the `protocol` for this instance.
//
Syslog.prototype.connect = function (callback) {
  var self = this, readyEvent;

  //
  // If the socket already exists then respond
  //
  if (this.socket) {
    return (!this.socket.readyState) || (this.socket.readyState === 'open')
      ? callback(null)
      : callback(true);
  }

  //
  // Create the appropriate socket type.
  //
  if (this.isDgram) {
    if (self.protocol.match(/^udp/)) {
      this.socket = new dgram.Socket(this.protocol);
    }
    else if (self.protocol === 'unix') {
      this.socket = new require('unix-dgram').createSocket('unix_dgram');
    }
    else {
      return this._unixDgramConnect(callback);
    }

    return callback(null);
  }
  else {
    this.socket = new net.Socket({ type: this.protocol });
    this.socket.setKeepAlive(true);
    this.socket.setNoDelay();
    readyEvent = 'connect';
  }

  //
  // On any error writing to the socket, emit the `logged` event
  // and the `error` event.
  //
  function onError(logErr) {
    if (logErr) { self.emit('error', logErr) }
    self.emit('logged');
    self.inFlight--;
  }

  //
  // Indicate to the callee that the socket is not ready. This
  // will enqueue the current message for later.
  //
  callback(true);

  //
  // Listen to the appropriate events on the socket that
  // was just created.
  //
  this.socket.on(readyEvent, function () {
    //
    // When the socket is ready, write the current queue
    // to it.
    //
    self.socket.write(self.queue.join(''), 'utf8', onError);

    self.emit('logged');
    self.queue = [];
    self.retries = 0;
    self.connected = true;
  }).on('error', function (ex) {
    //
    // TODO: Pass this error back up
    //
  }).on('end', function (ex) {
    //
    // Nothing needs to be done here.
    //
  }).on('close', function (ex) {
    //
    // Attempt to reconnect on lost connection(s), progressively
    // increasing the amount of time between each try.
    //
    var interval = Math.pow(2, self.retries);
    self.connected = false;

    setTimeout(function () {
      self.retries++;
      self.socket.connect(self.port, self.host);
    }, interval * 1000);
  }).on('timeout', function () {
    if (self.socket.readyState !== 'open') {
      self.socket.destroy();
    }
  });

  this.socket.connect(this.port, this.host);
};

Syslog.prototype._unixDgramConnect = function (cb) {
  var self = this;

  function flushQueue() {
    var sentMsgs = 0;
    self.queue.forEach(function (msg) {
      var buffer = new Buffer(msg);

      if (!self.congested) {
        self.socket.send(buffer, function () {
          ++sentMsgs;
        });
      }
    });

    self.queue.splice(0, sentMsgs);
  }

  this.socket = new unix.createSocket('unix_dgram');
  this.socket.on('error', function (err) {
    if (err.syscall === 'connect') {
      self.socket = null;
      cb(err);
    }

    self.emit('error', err);
  });

  this.socket.on('connect', function () {
    this.on('congestion', function () {
      self.congested = true;
    });

    this.on('writable', function () {
      self.congested = false;
      flushQueue();
    });

    flushQueue();
    cb();
  });

  this.socket.connect(this.path);
};
<commit_msg>[unix-dgram] Some fixes in unix-dgram sockets creation<commit_after>/*
 * syslog.js: Transport for logging to a remote syslog consumer
 *
 * (C) 2011 Squeeks and Charlie Robbins
 * MIT LICENCE
 *
 */

var dgram = require('dgram'),
    net = require('net'),
    util = require('util'),
    cycle = require('cycle'),
    glossy = require('glossy'),
    winston = require('winston'),
    common = require('winston/lib/winston/common');

var levels = Object.keys({
  debug: 0,
  info: 1,
  notice: 2,
  warning: 3,
  error: 4,
  crit: 5,
  alert: 6,
  emerg: 7
});

//
// ### function Syslog (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Syslog Transport capable of sending
// RFC 3164 and RFC 5424 compliant messages.
//
var Syslog = exports.Syslog = function (options) {
  winston.Transport.call(this, options);
  options = options || {};
  // Set transport name
  this.name = 'syslog';
  //
  // Setup connection state
  //
  this.connected = false;
  this.congested = false;
  this.retries = 0;
  this.queue = [];
  this.inFlight = 0;

  this.json        = options.json        || false;
  this.colorize    = options.colorize    || false;
  this.prettyPrint = options.prettyPrint || false;
  this.timestamp   = typeof options.timestamp !== 'undefined' ? options.timestamp : false;
  this.showLevel   = options.showLevel === undefined ? true : options.showLevel;
  this.label       = options.label       || null;
  this.logstash    = options.logstash    || false;
  this.depth       = options.depth       || null;

  //
  // Merge the options for the target Syslog server.
  //
  this.host     = options.host     || 'localhost';
  this.port     = options.port     || 514;
  this.path     = options.path     || null;
  this.appId    = options.appId    || options.app_id || null;
  this.protocol = options.protocol || 'udp4';
  this.isDgram  = /^udp|^unix/.test(this.protocol);
  this.endOfLine = options.eol;

  if (!/^udp|unix|unix-connect|tcp/.test(this.protocol)) {
    throw new Error('Invalid syslog protocol: ' + this.protocol);
  }

  if (/^unix/.test(this.protocol) && !this.path) {
    throw new Error('`options.path` is required on unix dgram sockets.');
  }

  //
  // Merge the default message options.
  //
  this.localhost = options.localhost || 'localhost';
  this.type      = options.type      || 'BSD';
  this.facility  = options.facility  || 'local0';
  this.pid       = options.pid       || process.pid;
  this.appName   = options.appName   || options.app_name  || process.title;

  //
  // Setup our Syslog and network members for later use.
  //
  this.socket   = null;
  this.producer = new glossy.Produce({
    type:     this.type,
    appName:  this.appName,
    pid:      this.pid,
    facility: this.facility
  });
};

//
// Inherit from `winston.Transport`.
//
util.inherits(Syslog, winston.Transport);

//
// Define a getter so that `winston.transports.Syslog`
// is available and thus backwards compatible.
//
winston.transports.Syslog = Syslog;

//
// Expose the name of this Transport on the prototype
//
Syslog.prototype.name = 'Syslog';
//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Target level to log to
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to log.
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Logs the `msg` and optional
// metadata, `meta`, to the specified `level`.
//
Syslog.prototype.log = function (level, msg, meta, callback) {
  var self = this,
      syslogMsg,
      buffer;

  if (!~levels.indexOf(level)) {
    return callback(new Error('Cannot log unknown syslog level: ' + level));
  }

  var output = common.log({
    colorize:    this.colorize,
    json:        this.json,
    level:       level,
    message:     msg,
    meta:        meta,
    stringify:   this.stringify,
    timestamp:   this.timestamp,
    showLevel:   this.showLevel,
    prettyPrint: this.prettyPrint,
    raw:         this.raw,
    label:       this.label,
    logstash:    this.logstash,
    depth:       this.depth,
    formatter:   this.formatter,
    humanReadableUnhandledException: this.humanReadableUnhandledException
  });

  syslogMsg = this.producer.produce({
    severity: level,
    host:     this.localhost,
    app_id:   this.appId || process.title,
    date:     new Date(),
    message:  this.endOfLine ? output + this.endOfLine : output
  });

  //
  // Attempt to connect to the socket
  //
  this.connect(function (err) {
    if (err) {
      //
      // If there was an error enqueue the message
      //
      self.queue.push(syslogMsg);

      return callback(err);
    }

    //
    // On any error writing to the socket, enqueue the message
    //
    function onError(logErr) {
      if (logErr) { self.queue.push(syslogMsg) }
      self.emit('logged');
      self.inFlight--;
    }

    function onCongestion() {
      onError(new Error('Congestion Error'));
    }

    //
    // Write to the `tcp*`, `udp*`, or `unix` socket.
    //
    if (self.isDgram) {
      buffer = new Buffer(syslogMsg);

      if (self.protocol.match(/^udp/)) {
        self.inFlight++;
        self.socket.send(buffer, 0, buffer.length, self.port, self.host, onError);
      }
      else if (self.protocol === 'unix') {
        self.socket.send(buffer, 0, buffer.length, self.path, onError);
      }
      else {
        if (self.congested) {
          self.queue.push(syslogMsg);
        }
        else {
          self.socket.once('congestion', onCongestion);
          self.socket.once('error', onError);
          self.socket.send(buffer, function () {
            self.socket.removeListener('congestion', onCongestion);
            self.socket.removeListener('error', onError);
            onError();
          });
        }
      }
    }
    else {
      self.socket.write(syslogMsg, 'utf8', onError);
    }

    callback(null, true);
  });
};
//
// ### function close ()
// Closes the socket used by this transport freeing the resource.
//
Syslog.prototype.close = function () {
  var self = this,
      max = 6,
      attempt = 0;

  (function _close() {
    if (attempt >= max || (self.queue.length === 0 && self.inFlight <= 0)) {
      if (self.socket) {
        self.socket.close();
      }

      self.emit('closed', self.socket);
    }
    else {
      attempt++;
      setTimeout(_close, 200 * attempt);
    }
  }());
};

//
// ### function connect (callback)
// #### @callback {function} Continuation to respond to when complete.
// Connects to the remote syslog server using `dgram` or `net` depending
// on the `protocol` for this instance.
//
Syslog.prototype.connect = function (callback) {
  var self = this, readyEvent;

  //
  // If the socket already exists then respond
  //
  if (this.socket) {
    return (!this.socket.readyState) || (this.socket.readyState === 'open')
      ? callback(null)
      : callback(true);
  }

  //
  // Create the appropriate socket type.
  //
  if (this.isDgram) {
    if (self.protocol.match(/^udp/)) {
      this.socket = new dgram.Socket(this.protocol);
    }
    else if (self.protocol === 'unix') {
      this.socket = require('unix-dgram').createSocket('unix_dgram');
    }
    else {
      return this._unixDgramConnect(callback);
    }

    return callback(null);
  }
  else {
    this.socket = new net.Socket({ type: this.protocol });
    this.socket.setKeepAlive(true);
    this.socket.setNoDelay();
    readyEvent = 'connect';
  }

  //
  // On any error writing to the socket, emit the `logged` event
  // and the `error` event.
  //
  function onError(logErr) {
    if (logErr) { self.emit('error', logErr) }
    self.emit('logged');
    self.inFlight--;
  }

  //
  // Indicate to the callee that the socket is not ready. This
  // will enqueue the current message for later.
  //
  callback(true);

  //
  // Listen to the appropriate events on the socket that
  // was just created.
  //
  this.socket.on(readyEvent, function () {
    //
    // When the socket is ready, write the current queue
    // to it.
    //
    self.socket.write(self.queue.join(''), 'utf8', onError);

    self.emit('logged');
    self.queue = [];
    self.retries = 0;
    self.connected = true;
  }).on('error', function (ex) {
    //
    // TODO: Pass this error back up
    //
  }).on('end', function (ex) {
    //
    // Nothing needs to be done here.
    //
  }).on('close', function (ex) {
    //
    // Attempt to reconnect on lost connection(s), progressively
    // increasing the amount of time between each try.
    //
    var interval = Math.pow(2, self.retries);
    self.connected = false;

    setTimeout(function () {
      self.retries++;
      self.socket.connect(self.port, self.host);
    }, interval * 1000);
  }).on('timeout', function () {
    if (self.socket.readyState !== 'open') {
      self.socket.destroy();
    }
  });

  this.socket.connect(this.port, this.host);
};

Syslog.prototype._unixDgramConnect = function (cb) {
  var self = this;

  function flushQueue() {
    var sentMsgs = 0;
    self.queue.forEach(function (msg) {
      var buffer = new Buffer(msg);

      if (!self.congested) {
        self.socket.send(buffer, function () {
          ++sentMsgs;
        });
      }
    });

    self.queue.splice(0, sentMsgs);
  }

  this.socket = require('unix-dgram').createSocket('unix_dgram');
  this.socket.on('error', function (err) {
    if (err.syscall === 'connect') {
      self.socket = null;
      cb(err);
    }

    self.emit('error', err);
  });

  this.socket.on('connect', function () {
    this.on('congestion', function () {
      self.congested = true;
    });

    this.on('writable', function () {
      self.congested = false;
      flushQueue();
    });

    flushQueue();
    cb();
  });

  this.socket.connect(this.path);
};
<|endoftext|>


<commit_before><commit_msg>Enabled source maps<commit_after><|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require("./logger.js")(__filename);

const firewalla = require('./Firewalla.js');
const HostTool = require('./HostTool.js');
const hostTool = new HostTool();

const ip = require('ip');

const exec = require('child-process-promise').exec

const sem = require('../sensor/SensorEventManager.js').getInstance();

const util = require('util');

const sclient = require('../util/redis_manager.js').getSubscriptionClient();
var instance = null;

class ShieldManager {
  constructor() {
    if (!instance) {
      sclient.on("message", (channel, message) => {
        switch (channel) {
          case "System:VPNSubnetChanged":
            const newVpnSubnet = message;
            this._updateVPNOutgoingRules(newVpnSubnet);
            break;
          default:

        }
      });
      if (firewalla.isMain()) {
        sclient.subscribe("System:VPNSubnetChanged");

        sem.on("DeviceUpdate", (event) => {
          // add/update device ip address to trusted_ip_set/trusted_ip_set_6
          const host = event.host;
          if (host.ipv4Addr) {
            log.info("Update device ip in trusted_ip_set: " + host.ipv4Addr);
            const cmd = util.format("sudo ipset add -! trusted_ip_set %s", host.ipv4Addr);
            exec(cmd);
          }
          if (host.ipv6Addr && host.ipv6Addr.length > 0) {
            host.ipv6Addr.forEach(ipv6Addr => {
              log.info("New device found add to trusted_ip_set6: " + ipv6Addr);
              const cmd = util.format("sudo ipset add -! trusted_ip_set6 %s", ipv6Addr);
              exec(cmd);
            });
          }
        });

        this._updateProtectedIPSet();
        setInterval(() => {
          this._updateProtectedIPSet();
        }, 300000); // update protected_mac_set once every 5 minutes
      }
    }
    return instance;
  }

  async addIncomingRule(protocol, dstIp, dstPort) {
    log.info(util.format("Add incoming rule to %s:%s, protocol %s", dstIp, dstPort, protocol));
    const cmd = util.format("sudo iptables -w -C FW_SHIELD -p %s -d %s --dport %s -j RETURN || sudo iptables -w -I FW_SHIELD -p %s -d %s --dport %s -j RETURN",
      protocol, dstIp, dstPort, protocol, dstIp, dstPort);
    await exec(cmd);
  }

  async removeIncomingRule(protocol, dstIp, dstPort) {
    log.info(util.format("Remove incoming rule to %s:%s, protocol %s", dstIp, dstPort, protocol));
    const cmd = util.format("sudo iptables -w -C FW_SHIELD -p %s -d %s --dport %s -j RETURN && sudo iptables -w -D FW_SHIELD -p %s -d %s --dport %s -j RETURN",
      protocol, dstIp, dstPort, protocol, dstIp, dstPort);
    await exec(cmd);
  }

  async _updateProtectedIPSet() {
    const macEntries = await hostTool.getAllMACEntries();
    for (let i in macEntries) {
      const macEntry = macEntries[i];
      const ipv4Addr = macEntry.ipv4Addr;
      if (ipv4Addr && ip.isV4Format(ipv4Addr)) {
        log.info("Add ip to trusted_ip_set: " + ipv4Addr);
        const cmd = util.format("sudo ipset add -! trusted_ip_set %s", ipv4Addr);
        await exec(cmd);
      }
      const ipv6Addrs = macEntry.ipv6Addr;
      if (ipv6Addrs && ipv6Addrs.length > 0) {
        for (let j in ipv6Addrs) {
          const ipv6Addr = ipv6Addrs[j];
          if (ipv6Addr && ip.isV6Format(ipv6Addr)) {
            log.info("Add ip to trusted_ip_set6: " + ipv6Addr);
            const cmd = util.format("sudo ipset add -! trusted_ip_set6 %s", ipv6Addr);
            await exec(cmd);
          }
        }
      }
    }
  }

  async _updateVPNOutgoingRules(vpnSubnet) {
    if (this.vpnSubnet) {
      // remove old vpn subnet
      const cmd = util.format("sudo iptables -w -C FW_SHIELD -p all -s %s -j RETURN && sudo iptables -w -D FW_SHIELD -p all -s %s -j RETURN", this.vpnSubnet, this.vpnSubnet);
      await exec(cmd);
      this.vpnSubnet = null;
    }
    if (vpnSubnet) {
      // add new vpn rule
      const cmd = util.format("sudo iptables -w -C FW_SHIELD -p all -s %s -j RETURN || sudo iptables -w -I FW_SHIELD -p all -s %s -j RETURN", vpnSubnet, vpnSubnet);
      await exec(cmd);
      this.vpnSubnet = vpnSubnet;
    }
  }

  async activateShield() {
    // append FW_SHIELD chain to FORWARD chain
    let cmd = "sudo iptables -w -C FORWARD -j FW_SHIELD || sudo iptables -w -A FORWARD -j FW_SHIELD";
    await exec(cmd);

    cmd = "sudo ip6tables -w -C FORWARD -j FW_SHIELD || sudo ip6tables -w -A FORWARD -j FW_SHIELD";
    await exec(cmd);
  }

  async deactivateShield() {
    // remove FW_SHIELD chain from FORWARD chain
    let cmd = "sudo iptables -w -C FORWARD -j FW_SHIELD && sudo iptables -w -D FORWARD -j FW_SHIELD";
    await exec(cmd);

    cmd = "sudo ip6tables -w -C FORWARD -j FW_SHIELD && sudo ip6tables -w -D FORWARD -j FW_SHIELD";
    await exec(cmd);
  }
}

module.exports = ShieldManager;<commit_msg>parse ipv6Addr of mac entry in advance in ShieldManager.js<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require("./logger.js")(__filename);

const firewalla = require('./Firewalla.js');
const HostTool = require('./HostTool.js');
const hostTool = new HostTool();

const ip = require('ip');

const exec = require('child-process-promise').exec

const sem = require('../sensor/SensorEventManager.js').getInstance();

const util = require('util');

const sclient = require('../util/redis_manager.js').getSubscriptionClient();
var instance = null;

class ShieldManager {
  constructor() {
    if (!instance) {
      sclient.on("message", (channel, message) => {
        switch (channel) {
          case "System:VPNSubnetChanged":
            const newVpnSubnet = message;
            this._updateVPNOutgoingRules(newVpnSubnet);
            break;
          default:

        }
      });
      if (firewalla.isMain()) {
        sclient.subscribe("System:VPNSubnetChanged");

        sem.on("DeviceUpdate", (event) => {
          // add/update device ip address to trusted_ip_set/trusted_ip_set_6
          const host = event.host;
          if (host.ipv4Addr) {
            log.info("Update device ip in trusted_ip_set: " + host.ipv4Addr);
            const cmd = util.format("sudo ipset add -! trusted_ip_set %s", host.ipv4Addr);
            exec(cmd);
          }
          if (host.ipv6Addr && host.ipv6Addr.length > 0) {
            host.ipv6Addr.forEach(ipv6Addr => {
              log.info("New device found add to trusted_ip_set6: " + ipv6Addr);
              const cmd = util.format("sudo ipset add -! trusted_ip_set6 %s", ipv6Addr);
              exec(cmd);
            });
          }
        });

        this._updateProtectedIPSet();
        setInterval(() => {
          this._updateProtectedIPSet();
        }, 300000); // update protected_mac_set once every 5 minutes
      }
    }
    return instance;
  }

  async addIncomingRule(protocol, dstIp, dstPort) {
    log.info(util.format("Add incoming rule to %s:%s, protocol %s", dstIp, dstPort, protocol));
    const cmd = util.format("sudo iptables -w -C FW_SHIELD -p %s -d %s --dport %s -j RETURN || sudo iptables -w -I FW_SHIELD -p %s -d %s --dport %s -j RETURN",
      protocol, dstIp, dstPort, protocol, dstIp, dstPort);
    await exec(cmd);
  }

  async removeIncomingRule(protocol, dstIp, dstPort) {
    log.info(util.format("Remove incoming rule to %s:%s, protocol %s", dstIp, dstPort, protocol));
    const cmd = util.format("sudo iptables -w -C FW_SHIELD -p %s -d %s --dport %s -j RETURN && sudo iptables -w -D FW_SHIELD -p %s -d %s --dport %s -j RETURN",
      protocol, dstIp, dstPort, protocol, dstIp, dstPort);
    await exec(cmd);
  }

  async _updateProtectedIPSet() {
    const macEntries = await hostTool.getAllMACEntries();
    for (let i in macEntries) {
      const macEntry = macEntries[i];
      const ipv4Addr = macEntry.ipv4Addr;
      if (ipv4Addr && ip.isV4Format(ipv4Addr)) {
        log.info("Add ip to trusted_ip_set: " + ipv4Addr);
        const cmd = util.format("sudo ipset add -! trusted_ip_set %s", ipv4Addr);
        await exec(cmd);
      }
      let ipv6Addrs = [];
      if (macEntry.ipv6Addr)
        ipv6Addrs = JSON.parse(macEntry.ipv6Addr);
      if (ipv6Addrs && ipv6Addrs.length > 0) {
        for (let j in ipv6Addrs) {
          const ipv6Addr = ipv6Addrs[j];
          if (ipv6Addr && ip.isV6Format(ipv6Addr)) {
            log.info("Add ip to trusted_ip_set6: " + ipv6Addr);
            const cmd = util.format("sudo ipset add -! trusted_ip_set6 %s", ipv6Addr);
            await exec(cmd);
          }
        }
      }
    }
  }

  async _updateVPNOutgoingRules(vpnSubnet) {
    if (this.vpnSubnet) {
      // remove old vpn subnet
      const cmd = util.format("sudo iptables -w -C FW_SHIELD -p all -s %s -j RETURN && sudo iptables -w -D FW_SHIELD -p all -s %s -j RETURN", this.vpnSubnet, this.vpnSubnet);
      await exec(cmd);
      this.vpnSubnet = null;
    }
    if (vpnSubnet) {
      // add new vpn rule
      const cmd = util.format("sudo iptables -w -C FW_SHIELD -p all -s %s -j RETURN || sudo iptables -w -I FW_SHIELD -p all -s %s -j RETURN", vpnSubnet, vpnSubnet);
      await exec(cmd);
      this.vpnSubnet = vpnSubnet;
    }
  }

  async activateShield() {
    // append FW_SHIELD chain to FORWARD chain
    let cmd = "sudo iptables -w -C FORWARD -j FW_SHIELD || sudo iptables -w -A FORWARD -j FW_SHIELD";
    await exec(cmd);

    cmd = "sudo ip6tables -w -C FORWARD -j FW_SHIELD || sudo ip6tables -w -A FORWARD -j FW_SHIELD";
    await exec(cmd);
  }

  async deactivateShield() {
    // remove FW_SHIELD chain from FORWARD chain
    let cmd = "sudo iptables -w -C FORWARD -j FW_SHIELD && sudo iptables -w -D FORWARD -j FW_SHIELD";
    await exec(cmd);

    cmd = "sudo ip6tables -w -C FORWARD -j FW_SHIELD && sudo ip6tables -w -D FORWARD -j FW_SHIELD";
    await exec(cmd);
  }
}

module.exports = ShieldManager;<|endoftext|>


<commit_before><commit_msg>minor update<commit_after><|endoftext|>