<commit_before>// Karma configuration
// Install required modules by running "npm install"

module.exports = function(config) {
  config.set({
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '.',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: [
      'jasmine-ajax', 'jasmine',
      'sprintf-js',
    ],

    plugins: [
      'karma-*',  // default
      frameworkPluginForModule('sprintf-js'),
    ],

    // list of files / patterns to load in the browser
    files: [
      // closure base first
      'third_party/closure/goog/base.js',

      // deps next
      'dist/deps.js',
      'shaka-player.uncompiled.js',

      // test utils next
      'test/util/*.js',

      // actual tests last
      'test/*.js',

      // source files - these are only watched and served
      {pattern: 'lib/**/*.js', included: false},
      {pattern: 'test/assets/*', included: false},
      {pattern: 'third_party/closure/goog/**/*.js', included: false},
    ],

    proxies: {
      '/test/assets/': '/base/test/assets/',
    },

    preprocessors: {
      // Don't compute coverage over lib/debug/ or lib/polyfill/
      'lib/!(debug|polyfill)/*.js': 'coverage',
      // Player is not matched by the above, so add it explicitly
      'lib/player.js': 'coverage',
    },

    coverageReporter: {
      reporters: [
        { type: 'text' },
      ],
    },

    // do not panic about "no activity" unless a test takes longer than 60s.
    browserNoActivityTimeout: 60000,

    // don't capture the client's console logs
    client: { captureConsole: true },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR ||
    //                  config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_WARN,

    // do not execute tests whenever any file changes
    autoWatch: false,

    // do a single run of the tests on captured browsers and then quit
    singleRun: true,

    customLaunchers: {
      // BrowserStack launchers require login information in the form of
      // the environment variables BROWSER_STACK_USERNAME and
      // BROWSER_STACK_ACCESS_KEY.
      BrowserStack_IE11: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '11.0',
        os: 'Windows',
        os_version: '8.1',
      },

      BrowserStack_Safari: {
        base: 'BrowserStack',
        browser: 'safari',
        browser_version: '8.0',
        os: 'OS X',
        os_version: 'Yosemite',
      },
    },

    browserStack: {
      // Always start a tunnel if using BrowserStack.  This used to be default,
      // but is now required as an explicit parameter.
      startTunnel: true
    },

    // By default, use Chrome only, unless command-line arguments override.
    browsers: ['Chrome'],
  });

  if (flagPresent('html-coverage-report')) {
    // Wipe out any old coverage reports to avoid confusion.
    var rimraf = require('rimraf');
    rimraf.sync('coverage', {});  // Like rm -rf

    config.set({
      reporters: [ 'coverage' ],
      coverageReporter: {
        reporters: [
          { type: 'html', dir: 'coverage' },
        ],
      },
    });
  }
};

// Find custom command-line flags.
function flagPresent(name) {
  return process.argv.indexOf('--' + name) >= 0;
}

// Construct framework plugins on-the-fly for arbitrary node modules.
// A call to this must be placed in the config in the 'plugins' array,
// and the module name must be added to the config in the 'frameworks' array.
function frameworkPluginForModule(name) {
  // The framework injects files into the client which runs the tests.
  var framework = function(files) {
    // Locate the main file for the node module.
    var path = require('path');
    var mainFile = path.resolve(require.resolve(name));

    // Add a file entry to the list of files to be served.
    // This follows the same syntax as above in config.set({files: ...}).
    files.unshift({
      pattern: mainFile, included: true, served: true, watched: false
    });
  };

  // The framework factory function takes one argument, which is the list of
  // files from the karma config.
  framework.$inject = ['config.files'];

  // This is the plugin interface to register a new framework.  Adding this to
  // the list of plugins makes the named module available as a framework.  That
  // framework then injects the module into the client.
  var obj = {};
  obj['framework:' + name] = ['factory', framework];
  return obj;
}
<commit_msg>Show progress during coverage report<commit_after>// Karma configuration
// Install required modules by running "npm install"

module.exports = function(config) {
  config.set({
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '.',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: [
      'jasmine-ajax', 'jasmine',
      'sprintf-js',
    ],

    plugins: [
      'karma-*',  // default
      frameworkPluginForModule('sprintf-js'),
    ],

    // list of files / patterns to load in the browser
    files: [
      // closure base first
      'third_party/closure/goog/base.js',

      // deps next
      'dist/deps.js',
      'shaka-player.uncompiled.js',

      // test utils next
      'test/util/*.js',

      // actual tests last
      'test/*.js',

      // source files - these are only watched and served
      {pattern: 'lib/**/*.js', included: false},
      {pattern: 'test/assets/*', included: false},
      {pattern: 'third_party/closure/goog/**/*.js', included: false},
    ],

    proxies: {
      '/test/assets/': '/base/test/assets/',
    },

    preprocessors: {
      // Don't compute coverage over lib/debug/ or lib/polyfill/
      'lib/!(debug|polyfill)/*.js': 'coverage',
      // Player is not matched by the above, so add it explicitly
      'lib/player.js': 'coverage',
    },

    coverageReporter: {
      reporters: [
        { type: 'text' },
      ],
    },

    // do not panic about "no activity" unless a test takes longer than 60s.
    browserNoActivityTimeout: 60000,

    // don't capture the client's console logs
    client: { captureConsole: true },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR ||
    //                  config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_WARN,

    // do not execute tests whenever any file changes
    autoWatch: false,

    // do a single run of the tests on captured browsers and then quit
    singleRun: true,

    customLaunchers: {
      // BrowserStack launchers require login information in the form of
      // the environment variables BROWSER_STACK_USERNAME and
      // BROWSER_STACK_ACCESS_KEY.
      BrowserStack_IE11: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '11.0',
        os: 'Windows',
        os_version: '8.1',
      },

      BrowserStack_Safari: {
        base: 'BrowserStack',
        browser: 'safari',
        browser_version: '8.0',
        os: 'OS X',
        os_version: 'Yosemite',
      },
    },

    browserStack: {
      // Always start a tunnel if using BrowserStack.  This used to be default,
      // but is now required as an explicit parameter.
      startTunnel: true
    },

    // By default, use Chrome only, unless command-line arguments override.
    browsers: ['Chrome'],
  });

  if (flagPresent('html-coverage-report')) {
    // Wipe out any old coverage reports to avoid confusion.
    var rimraf = require('rimraf');
    rimraf.sync('coverage', {});  // Like rm -rf

    config.set({
      reporters: [ 'coverage', 'progress' ],
      coverageReporter: {
        reporters: [
          { type: 'html', dir: 'coverage' },
        ],
      },
    });
  }
};

// Find custom command-line flags.
function flagPresent(name) {
  return process.argv.indexOf('--' + name) >= 0;
}

// Construct framework plugins on-the-fly for arbitrary node modules.
// A call to this must be placed in the config in the 'plugins' array,
// and the module name must be added to the config in the 'frameworks' array.
function frameworkPluginForModule(name) {
  // The framework injects files into the client which runs the tests.
  var framework = function(files) {
    // Locate the main file for the node module.
    var path = require('path');
    var mainFile = path.resolve(require.resolve(name));

    // Add a file entry to the list of files to be served.
    // This follows the same syntax as above in config.set({files: ...}).
    files.unshift({
      pattern: mainFile, included: true, served: true, watched: false
    });
  };

  // The framework factory function takes one argument, which is the list of
  // files from the karma config.
  framework.$inject = ['config.files'];

  // This is the plugin interface to register a new framework.  Adding this to
  // the list of plugins makes the named module available as a framework.  That
  // framework then injects the module into the client.
  var obj = {};
  obj['framework:' + name] = ['factory', framework];
  return obj;
}
<|endoftext|>


<commit_before>var By = require('selenium-webdriver').By,
    until = require('selenium-webdriver').until,
    chrome = require('selenium-webdriver/chrome');

module.exports = function(config){
  config.set({
    basePath : './',

    files : [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-aria/angular-aria.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/bower_components/angular-material/angular-material.js',
      'app/components/**/*.js',
      'app/view*/**/*.js'
    ],

    frameworks: ['jasmine'],

    browsers : ['swd_chrome'],

    customLaunchers: {
        swd_chrome: {
            base: 'SeleniumWebDriver',
            browserName: 'Chrome',
            getDriver: function(){
              // example from https://www.npmjs.com/package/selenium-webdriver#usage
              var driver = new chrome.Driver();
              return driver;
            }
        },
    },

    /*plugins : [
            'karma-jasmine',
            'karma-junit-reporter'
            ],

    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }*/

  });
};
<commit_msg>Trying out parameter in karma config<commit_after>module.exports = function(config){
  config.set({
    basePath : './',

    files : [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-aria/angular-aria.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/bower_components/angular-material/angular-material.js',
      'app/components/**/*.js',
      'app/view*/**/*.js'
    ],

    frameworks: ['jasmine'],

    browsers : ['swd_chrome'],

    customLaunchers: {
        swd_chrome: {
            base: 'SeleniumWebDriver',
            browserName: 'Chrome',
            getDriver: function(){
              // example from https://www.npmjs.com/package/selenium-webdriver#usage
              var driver = new webdriver.Builder()
                      .forBrowser('chrome')
                      .usingServer('http://0.0.0.0:4444/wd/hub')
                      .build();
              return driver;
            }
        },
    },

    /*plugins : [
            'karma-jasmine',
            'karma-junit-reporter'
            ],

    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }*/

  });
};
<|endoftext|>


<commit_before>module.exports = function(config) {
  config.set({
    //logLevel: config.LOG_DEBUG,
    basePath: '.',
    frameworks: ['dart-unittest'],

    // list of files / patterns to load in the browser
    // all tests must be 'included', but all other libraries must be 'served' and
    // optionally 'watched' only.
    files: [
      'test/jasmine_syntax.dart',
      'test/*.dart',
      'test/**/*_spec.dart',
      'test/config/filter_tests.dart',
      {pattern: '**/*.dart', watched: true, included: false, served: true},
      'packages/browser/dart.js',
      'packages/browser/interop.js',
    ],

    exclude: [
      'test/io/**',
    ],

    autoWatch: false,

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 5000,

    plugins: [
      'karma-dart',
      'karma-chrome-launcher',
      'karma-script-launcher',
      'karma-phantomjs-launcher',
      'karma-junit-reporter',
      '../../../karma-parser-generator',
      '../../../karma-parser-getter-setter'
    ],

    customLaunchers: {
      Dartium: { base: 'ChromeCanary', flags: ['--no-sandbox'] },
      ChromeNoSandbox: { base: 'Chrome', flags: ['--no-sandbox'] }
    },

    preprocessors: {
      'test/core/parser/generated_functions.dart': ['parser-generator'],
      'test/core/parser/generated_getter_setter.dart': ['parser-getter-setter']
    },

    junitReporter: {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }
  });
};
<commit_msg>chore(karma): clean up karma config file syntax.<commit_after>module.exports = function(config) {
  config.set({
    //logLevel: config.LOG_DEBUG,
    basePath: '.',
    frameworks: ['dart-unittest'],

    // list of files / patterns to load in the browser
    // all tests must be 'included', but all other libraries must be 'served' and
    // optionally 'watched' only.
    files: [
      'test/jasmine_syntax.dart',
      'test/*.dart',
      'test/**/*_spec.dart',
      'test/config/filter_tests.dart',
      {pattern: '**/*.dart', watched: true, included: false, served: true},
      'packages/browser/dart.js',
      'packages/browser/interop.js'
    ],

    exclude: [
      'test/io/**'
    ],

    autoWatch: false,

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 5000,

    plugins: [
      'karma-dart',
      'karma-chrome-launcher',
      'karma-script-launcher',
      'karma-phantomjs-launcher',
      'karma-junit-reporter',
      '../../../karma-parser-generator',
      '../../../karma-parser-getter-setter'
    ],

    customLaunchers: {
      Dartium: { base: 'ChromeCanary', flags: ['--no-sandbox'] },
      ChromeNoSandbox: { base: 'Chrome', flags: ['--no-sandbox'] }
    },

    preprocessors: {
      'test/core/parser/generated_functions.dart': ['parser-generator'],
      'test/core/parser/generated_getter_setter.dart': ['parser-getter-setter']
    },

    junitReporter: {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }
  });
};
<|endoftext|>


<commit_before><commit_msg>Pin visibility fix<commit_after><|endoftext|>


<commit_before>function embedImage(imageSrc) {
    //This formatting is copied directly from thebombzen with slight modifications to make use of the DOM structure in HTML5

    var banner = document.createElement("DIV");
    banner.style.position = "fixed";
    banner.style.width = "100%";
    banner.style.margin = "0 0 0 -50%";
    banner.style.left = "50%";
    banner.style.visibility = "hidden";
    banner.style.textAlign = "center";
    banner.style.top = "15%";
    banner.onclick = function() {
        banner.style.visibility = "hidden";
    }

    var image = document.createElement("IMG");
    image.src = imageSrc;
    banner.appendChild(image);

    banner.style.z-index = 10;

    return banner;
}

function codeImagePair(combination, imageSrc) {
    var progress  = 0;
    var totalKeystrokes = combination.length;

    var image = embedImage(imageSrc);
    document.body.appendChild(image);

    var processInput = function(keyCode) {
        if(combination[progress] == keyCode) {
            progress++;
            if(progress >= totalKeystrokes) {
                image.style.visibility = "visible";
                progress = 0;
            }
        } else {
            progress = 0;
        }
    }

    var eventListener = function(e) {
        e = e || window.event;
        processInput(e.keyCode);
    }

    document.addEventListener("keydown", eventListener, false);
}

var konami = [38,38,40,40,37,39,37,39,66,65];
var vvvvvv = [86,86,86,86,86,86];
<commit_msg>made it so that konamiCode image has high z-index so it will show up in front of elements with normal z-index<commit_after>function embedImage(imageSrc) {
    //This formatting is copied directly from thebombzen with slight modifications to make use of the DOM structure in HTML5

    var banner = document.createElement("DIV");
    banner.style.position = "fixed";
    banner.style.width = "100%";
    banner.style.margin = "0 0 0 -50%";
    banner.style.left = "50%";
    banner.style.visibility = "hidden";
    banner.style.textAlign = "center";
    banner.style.top = "15%";
    banner.onclick = function() {
        banner.style.visibility = "hidden";
    }

    var image = document.createElement("IMG");
    image.src = imageSrc;
    banner.appendChild(image);

    banner.style.zIndex = "10";

    return banner;
}

function codeImagePair(combination, imageSrc) {
    var progress  = 0;
    var totalKeystrokes = combination.length;

    var image = embedImage(imageSrc);
    document.body.appendChild(image);

    var processInput = function(keyCode) {
        if(combination[progress] == keyCode) {
            progress++;
            if(progress >= totalKeystrokes) {
                image.style.visibility = "visible";
                progress = 0;
            }
        } else {
            progress = 0;
        }
    }

    var eventListener = function(e) {
        e = e || window.event;
        processInput(e.keyCode);
    }

    document.addEventListener("keydown", eventListener, false);
}

var konami = [38,38,40,40,37,39,37,39,66,65];
var vvvvvv = [86,86,86,86,86,86];
<|endoftext|>


<commit_before>import React, { Fragment, useState, useEffect } from "react";
import styled from "styled-components";
import Button from "@material-ui/core/Button";

var moment = require("moment");
import axios from "axios";

const Player = styled.div`
  display: grid;
  grid-template-columns: 190px 60px;
  grid-auto-rows: 35px;
  align-items: center;
`;

const CancelBtn = styled.div`
  cursor: pointer;
`;

const MatchWithPlayer = styled.div``;
const MatchToBePlanned = styled.div``;
const NoMatch = styled.div`
  margin-top: 20px;
`;
const PlanButton = styled(Button)`
  && {
    margin-left: 30px;
    margin-bottom: 10px;
  }
`;
const Title = styled.h3`
  font-size: 20px;
`;

const ScheduleMatch = ({ matchType }) => {
  const [scheduledMatches, setScheduledMatches] = useState([]);
  const [matchesList, setMatchesList] = useState([]);
  const [updateToggle, setUpdateToggle] = useState(false);
  const [matchToPlanCount, setMatchToPlanCount] = useState(0);

  useEffect(() => {
    async function fetchData() {
      const result = await axios(
        `/rest/seasons/current/matches/${matchType}/next`
      );
      setScheduledMatches(result.data);
    }

    fetchData();
  }, [updateToggle]);

  useEffect(() => {
    async function fetchData() {
      const result = await axios(
        `rest/seasons/current/matches/${matchType}/to-plan`
      );
      setMatchesList(result.data);
      setMatchToPlanCount(result.data.length);
    }

    fetchData();
  }, [matchToPlanCount]);

  const handleSubstitute = async (date, player) => {
    await axios.delete(
      `/rest/seasons/current/matches/${matchType}/${date}/players/${player}`
    );
    setUpdateToggle(!updateToggle);
  };

  const planHanlder = async date => {
    await axios.put(`/rest/seasons/current/matches/${matchType}/${date}`);
    setUpdateToggle(!updateToggle);
    setMatchToPlanCount(matchToPlanCount - 1);
  };

  const intersperse = (arr, sep) => {
    if (arr.length === 0) {
      return [];
    }
    return arr.slice(1).reduce((xs, x, i) => xs.concat([sep, x]), [arr[0]]);
  };

  return (
    <Fragment>
      {scheduledMatches.length > 0 && (
        <MatchWithPlayer>
          <Title>Next {matchType} matches</Title>
          {scheduledMatches.map(match => (
            <div key={`match-${match.date}`}>

{moment(match.date).format("dddd YYYY/MM/DD")}

              {match.players.map(player => (
                <Player key={`player-${player}`}>
                  {player}

                    {match.subs.length !== 0 && match.hasMinimumPlayer && (
                      <CancelBtn
                        onClick={() => handleSubstitute(match.date, player)}
                      >
                        ❎
                      </CancelBtn>
                    )}

                </Player>
              ))}
              Substitutes : {" "}
              {match.subs.length == 0 ? "None" : intersperse(match.subs, ", ")}

          ))}
        </MatchWithPlayer>
      )}
      {matchesList.length > 0 && (
        <MatchToBePlanned>
          <Title>Matches to plan</Title>
          {matchesList.map(match => (

              {match.date}
              <PlanButton
                color="primary"
                size="small"
                variant="contained"
                onClick={() => planHanlder(match.date)}
              >
                PLAN
              </PlanButton>

          ))}
        </MatchToBePlanned>
      )}
      {scheduledMatches.length === 0 && matchesList.length === 0 && (
        <NoMatch>No match to plan</NoMatch>
      )}
    </Fragment>
  );
};

export default ScheduleMatch;
<commit_msg>fix league subs<commit_after>import React, { Fragment, useState, useEffect } from "react";
import styled from "styled-components";
import Button from "@material-ui/core/Button";

var moment = require("moment");
import axios from "axios";

const Player = styled.div`
  display: grid;
  grid-template-columns: 190px 60px;
  grid-auto-rows: 35px;
  align-items: center;
`;

const CancelBtn = styled.div`
  cursor: pointer;
`;

const MatchWithPlayer = styled.div``;
const MatchToBePlanned = styled.div``;
const NoMatch = styled.div`
  margin-top: 20px;
`;
const PlanButton = styled(Button)`
  && {
    margin-left: 30px;
    margin-bottom: 10px;
  }
`;
const Title = styled.h3`
  font-size: 20px;
`;

const ScheduleMatch = ({ matchType }) => {
  const [scheduledMatches, setScheduledMatches] = useState([]);
  const [matchesList, setMatchesList] = useState([]);
  const [updateToggle, setUpdateToggle] = useState(false);
  const [matchToPlanCount, setMatchToPlanCount] = useState(0);

  useEffect(() => {
    async function fetchData() {
      const result = await axios(
        `/rest/seasons/current/matches/${matchType}/next`
      );
      setScheduledMatches(result.data);
    }

    fetchData();
  }, [updateToggle]);

  useEffect(() => {
    async function fetchData() {
      const result = await axios(
        `rest/seasons/current/matches/${matchType}/to-plan`
      );
      setMatchesList(result.data);
      setMatchToPlanCount(result.data.length);
    }

    fetchData();
  }, [matchToPlanCount]);

  const handleSubstitute = async (date, player) => {
    await axios.delete(
      `/rest/seasons/current/matches/${matchType}/${date}/players/${player}`
    );
    setUpdateToggle(!updateToggle);
  };

  const planHanlder = async date => {
    await axios.put(`/rest/seasons/current/matches/${matchType}/${date}`);
    setUpdateToggle(!updateToggle);
    setMatchToPlanCount(matchToPlanCount - 1);
  };

  const intersperse = (arr, sep) => {
    if (arr.length === 0) {
      return [];
    }
    return arr.slice(1).reduce((xs, x, i) => xs.concat([sep, x]), [arr[0]]);
  };

  return (
    <Fragment>
      {scheduledMatches.length > 0 && (
        <MatchWithPlayer>
          <Title>Next {matchType} matches</Title>
          {scheduledMatches.map(match => (
            <div key={`match-${match.date}`}>

{moment(match.date).format("dddd YYYY/MM/DD")}

              {match.players.map(player => (
                <Player key={`player-${player}`}>
                  {player}

                    {(match.subs.length !== 0 || (match.subs.length === 0 && !match.hasMinimumPlayer)) && (
                      <CancelBtn
                        onClick={() => handleSubstitute(match.date, player)}
                      >
                        ❎
                      </CancelBtn>
                    )}

                </Player>
              ))}
              Substitutes : {" "}
              {match.subs.length === 0 ? "None" : intersperse(match.subs, ", ")}

          ))}
        </MatchWithPlayer>
      )}
      {matchesList.length > 0 && (
        <MatchToBePlanned>
          <Title>Matches to plan</Title>
          {matchesList.map(match => (

              {match.date}
              <PlanButton
                color="primary"
                size="small"
                variant="contained"
                onClick={() => planHanlder(match.date)}
              >
                PLAN
              </PlanButton>

          ))}
        </MatchToBePlanned>
      )}
      {scheduledMatches.length === 0 && matchesList.length === 0 && (
        <NoMatch>No match to plan</NoMatch>
      )}
    </Fragment>
  );
};

export default ScheduleMatch;
<|endoftext|>


<commit_before>import React from 'react'
import glamorous from 'glamorous'
import content from './content/locale-chooser'
import EnSvg from './svgs/en.svg'
import EsSvg from './svgs/es.svg'
import FrSvg from './svgs/fr.svg'

const {supportedLocales, fallbackLocale} = require('../config.json')

const Wrapper = glamorous.div({
  fontSize: '.8em',
  cursor: 'pointer',
})

const Toggle = glamorous.button((props, {colors, mediaQueries}) => ({
  backgroundColor: colors.white,
  color: colors.primaryMed,
  border: `1px solid ${colors.primaryMed}`,
  textAlign: 'left',
  padding: '3px 10px',
  outline: 'none',
  display: 'block',
  fontSize: '1em',
  width: '100%',
  borderBottomColor: props.isOpen ? 'transparent' : colors.primaryMed,
  [mediaQueries.smallOnly]: {
    textAlign: 'center',
  },
}))

const List = glamorous.ul((props, {colors, mediaQueries}) => ({
  display: 'flex',
  position: 'absolute',
  flexDirection: 'column',
  padding: 0,
  margin: 0,
  opacity: '.9',
  border: `1px solid ${colors.primaryMed}`,
  [mediaQueries.smallOnly]: {
    position: 'relative',
    width: '100%',
  },
}))

const Item = glamorous.li((props, {colors, mediaQueries}) => ({
  display: 'flex',
  flex: 1,
  textAlign: 'left',
  margin: 0,
  backgroundColor: colors.white,
  lineHeight: 1,
  transition: 'all .3s',
  '&:focus, &:hover, &:active': {
    backgroundColor: colors.primaryMed,
  },
  [mediaQueries.smallOnly]: {
    textAlign: 'center',
  },
}))

const Link = glamorous.a((props, {colors}) => ({
  width: '100%',
  padding: '6px 10px',
  transition: 'all .3s',
  '&:focus, &:hover, &:active': {
    textDecoration: 'none',
    color: colors.white,
  },
}))

const localeContent = ({display, flag}) =>
  (

    {flag} {display}

)

const localeItem = ({key, display, flag}) =>
  (<Item key={key}>
    <Link href={localeToHref(key)}>
      {localeContent({flag, display})}
    </Link>
  </Item>)

class LocaleChooser extends React.Component {
  state = {
    open: false,
  }

  handleClick() {
    this.setState(prevState => {
      return {open: !prevState.open}
    })
  }

  render() {
    return (
      <Wrapper>
        <Toggle onClick={this.handleClick.bind(this)} isOpen={this.state.open}>
          {localeContent(mapLocale(process.env.LOCALE))}
        </Toggle>
        {this.state.open &&
          <List aria-label="Locale selector">
            {supportedLocales.map(l => localeItem(mapLocale(l)))}
            {localeItem(mapLocale('help'))}
          </List>}
      </Wrapper>
    )
  }
}
export default LocaleChooser

function localeToHref(locale) {
  if (supportedLocales.includes(locale)) {
    const {host} = getLocaleAndHost()
    const {protocol, pathname, hash, search} = window.location
    const prefix = fallbackLocale === locale ? '' : `${locale}.`
    return `${protocol}//${prefix}${host}${pathname}${search}${hash}`
  }

  return 'https://github.com/kentcdodds/glamorous-website/blob/master/other/CONTRIBUTING_DOCUMENTATION.md'
}

function getLocaleAndHost() {
  const locale = process.env.LOCALE
  const {host} = window.location
  // eslint-disable-next-line no-unused-vars
  const [localePart, ...rest] = host.split('.')
  if (supportedLocales.includes(locale)) {
    return {locale, host: rest.join('.')}
  } else {
    return {locale: fallbackLocale, host}
  }
}

function mapLocale(key) {
  const svgStyle = {width: '1em', height: '100%'}
  switch (key) {
    case 'en':
      return {
        key,
        display: 'English',
        flag: <EnSvg {...svgStyle} />,
      }
    case 'es':
      return {
        key,
        display: 'Español',
        flag: <EsSvg {...svgStyle} />,
      }
    case 'fr': {
      return {
        key,
        display: 'Français',
        flag: <FrSvg {...svgStyle} />,
      }
    }
    case 'help': {
      return {
        key,
        display: content.help,
      }
    }
    default: {
      return {
        key,
        display: key,
      }
    }
  }
}
<commit_msg>fix locale chooser thing<commit_after>import React from 'react'
import glamorous from 'glamorous'
import content from './content/locale-chooser'
import EnSvg from './svgs/en.svg'
import EsSvg from './svgs/es.svg'
import FrSvg from './svgs/fr.svg'

const {supportedLocales, fallbackLocale} = require('../config.json')

const Wrapper = glamorous.div({
  fontSize: '.8em',
  cursor: 'pointer',
})

const Toggle = glamorous.button((props, {colors, mediaQueries}) => ({
  backgroundColor: colors.white,
  color: colors.primaryMed,
  border: `1px solid ${colors.primaryMed}`,
  textAlign: 'left',
  padding: '3px 10px',
  outline: 'none',
  display: 'block',
  fontSize: '1em',
  width: '100%',
  borderBottomColor: props.isOpen ? 'transparent' : colors.primaryMed,
  [mediaQueries.smallOnly]: {
    textAlign: 'center',
  },
}))

const List = glamorous.ul((props, {colors, mediaQueries}) => ({
  display: 'flex',
  position: 'absolute',
  flexDirection: 'column',
  padding: 0,
  margin: 0,
  opacity: '.9',
  border: `1px solid ${colors.primaryMed}`,
  [mediaQueries.smallOnly]: {
    position: 'relative',
    width: '100%',
  },
}))

const Item = glamorous.li((props, {colors, mediaQueries}) => ({
  display: 'flex',
  flex: 1,
  textAlign: 'left',
  margin: 0,
  backgroundColor: colors.white,
  lineHeight: 1,
  transition: 'all .3s',
  '&:focus, &:hover, &:active': {
    backgroundColor: colors.primaryMed,
  },
  [mediaQueries.smallOnly]: {
    textAlign: 'center',
  },
}))

const Link = glamorous.a((props, {colors}) => ({
  width: '100%',
  padding: '6px 10px',
  transition: 'all .3s',
  '&:focus, &:hover, &:active': {
    textDecoration: 'none',
    color: colors.white,
  },
}))

const localeContent = ({display, flag}) =>
  (

    {flag} {display}

)

const localeItem = ({key, display, flag}) =>
  (<Item key={key}>
    <Link href={localeToHref(key)}>
      {localeContent({flag, display})}
    </Link>
  </Item>)

class LocaleChooser extends React.Component {
  state = {
    open: false,
  }

  handleClick() {
    this.setState(prevState => {
      return {open: !prevState.open}
    })
  }

  render() {
    return (
      <Wrapper>
        <Toggle onClick={this.handleClick.bind(this)} isOpen={this.state.open}>
          {localeContent(mapLocale(process.env.LOCALE))}
        </Toggle>
        {this.state.open &&
          <List aria-label="Locale selector">
            {supportedLocales.map(l => localeItem(mapLocale(l)))}
            {localeItem(mapLocale('help'))}
          </List>}
      </Wrapper>
    )
  }
}
export default LocaleChooser

function localeToHref(locale) {
  if (supportedLocales.includes(locale)) {
    const {host} = getLocaleAndHost()
    const {protocol, pathname, hash, search} = window.location
    const prefix = fallbackLocale === locale ? '' : `${locale}.`
    return `${protocol}//${prefix}${host}${pathname}${search}${hash}`
  }

  return 'https://github.com/kentcdodds/glamorous-website/blob/master/other/CONTRIBUTING_DOCUMENTATION.md'
}

function getLocaleAndHost() {
  const locale = process.env.LOCALE
  const {host} = window.location
  // eslint-disable-next-line no-unused-vars
  const [localePart, ...rest] = host.split('.')
  if (supportedLocales.includes(locale) || localePart !== locale) {
    return {locale, host: rest.join('.')}
  } else {
    return {locale: fallbackLocale, host}
  }
}

function mapLocale(key) {
  const svgStyle = {width: '1em', height: '100%'}
  switch (key) {
    case 'en':
      return {
        key,
        display: 'English',
        flag: <EnSvg {...svgStyle} />,
      }
    case 'es':
      return {
        key,
        display: 'Español',
        flag: <EsSvg {...svgStyle} />,
      }
    case 'fr': {
      return {
        key,
        display: 'Français',
        flag: <FrSvg {...svgStyle} />,
      }
    }
    case 'help': {
      return {
        key,
        display: content.help,
      }
    }
    default: {
      return {
        key,
        display: key,
      }
    }
  }
}
<|endoftext|>


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

var app = require('commander')
var getLists = require('./util/get-lists')

app
  .description('Export your data')
  .parse(process.argv)

getLists(function (err, data) {
  if (err) process.exit(1)

  var ex = {
    data: {
      exported_at: new Date(),
      lists: data
    }
  }

  console.log(JSON.stringify(ex, null, 2))
})
<commit_msg>cleanup<commit_after>#!/usr/bin/env node

var app = require('commander')
var async = require('async')
var api = require('./util/api')

app
  .description('Export your data')
  .parse(process.argv)

function progress() {
  process.stderr.write('.')
}

async.waterfall([
  function (callback) {
    api.get('/user', function (err, res, body) {
      progress()
      callback(null, {user: body})
    })
  },
  function (data, callback) {
    api.get('/lists', function (err, res, body) {
      progress()
      data.user.lists = body
      callback(null, data)
    })
  },
  function (data, callback) {
    var tasks = []
    async.eachLimit(data.user.lists, 4, function (list, complete) {
      api.get({url: '/tasks', qs: {list_id: list.id}}, function (err, res, body) {
        progress()
        tasks[list.id] = body
        complete()
      })
    }, function () {
      data.user.lists.forEach(function (list, index) {
        data.user.lists[index].tasks = tasks[list.id]
      })
      callback(null, data)
    })
  }
], function (err, data) {
  process.stdout.write(JSON.stringify({data: data}, null, 2))
});
<|endoftext|>


<commit_before>/* ***********************************************************************************************

    Unify Project

    Homepage: unify-project.org
    License: MIT + Apache (V2)
    Copyright: 2012 Deutsche Telekom AG, Germany, http://telekom.com

*********************************************************************************************** */

(function() {

  /**
   * The ID of the CLOSE button. (The one in the right upper corner)
   */
  var BTN_CLOSE = "CLOSE";

  /**
   * The ID of the default OK button
   */
  var BTN_OK = "OK";

  /**
   * Generic modular dialog
   */
  core.Class("unify.ui.dialog.GenericDialog", {
    include: [
              unify.ui.container.Composite,
              unify.ui.core.MChildControl,
              unify.ui.core.MRemoteChildrenHandling
             ],
    implement : [unify.ui.core.IPopOver],

    /*
     *****************************************************************************
       EVENTS
     *****************************************************************************
     */

    events: {
      /** This event is fired when the dialog is closed by pressing a button */
      "execute": lowland.events.DataEvent, //"qx.event.type.Data"
    },

    /**
     * Creates a new generic dialog
     *
     * @param title {String} Title of dialog
     * @param buttons {Array} Array of buttons
     */
    construct: function(title, buttons) {
      unify.ui.container.Composite.call(this, new unify.ui.layout.VBox());
      unify.ui.core.MChildControl.call(this);
      unify.ui.core.MRemoteChildrenHandling.call(this);

      this.__createUI(title, buttons);
    },

    /*
     *****************************************************************************
       PROPERTIES
     *****************************************************************************
     */
    properties : {
      // overridden
      appearance : {
        init: "dialog"
      }
    },

    /*
     *****************************************************************************
       MEMBERS
     *****************************************************************************
     */
    members : {

      // TODO:
      indexOf : function() {
        return unify.ui.core.MRemoteChildrenHandling.prototype.indexOf.apply(this, arguments);
      },
      add : function() {
        unify.ui.core.MRemoteChildrenHandling.prototype.add.apply(this, arguments);
      },
      getChildren : function() {
        return unify.ui.core.MRemoteChildrenHandling.prototype.getChildren.apply(this, arguments);
      },
      setStyle : function() {
        unify.ui.core.MRemoteChildrenHandling.prototype.setStyle.apply(this, arguments);
      },
      // TODO DONE

      getModal : function() {
        return true;
      },

      /**
       * Get children container that is accessed via remote child handling
       *
       * @return {unify.ui.core.Widget} Container
       */
      getChildrenContainer : function() {
        return this.getChildControl("content");
      },

      /**
       * Creates child controls
       *
       * @param id {String} ID of control
       * @return {unify.ui.core.Widget} Widget
       */
      _createChildControlImpl : function(id) {
        var control;

        if (id == "X") {
          // close button (right upper corner)
          control = new unify.ui.form.Button("Close");
          this._add(control);
        } else if (id == "title") {
          control = new unify.ui.basic.Label();
          control.set({
            alignX: "center",
            alignY: "bottom"
          });
          this._add(control);
        } else if (id == "content") {
          control = new unify.ui.container.Composite(new unify.ui.layout.VBox());
          control.set({
            allowGrowX: true,
            allowGrowY: true,
            allowShrinkX: true,
            allowShrinkY: true
          });
          this._add(control, { flex: 1 });
        } else if (id == "buttons") {
          control = new unify.ui.container.Composite(new unify.ui.layout.HBox(10));
          control.set({
            allowGrowX: true,
            allowGrowY: false,
            allowShrinkX: true,
            allowShrinkY: false
          });
          this._add(control);
        }

        return control; // || this.base(arguments, id);
      },

      /**
       * Creates UI
       *
       * @param title {String} Title of UI
       * @param buttons {Array} Array of buttons to show
       */
      __createUI : function(title, buttons) {
        var X = this._showChildControl("X");
        X.addListener("execute", this.__onButtonExecute, this);
        X.setUserData("id", BTN_CLOSE);

        this._showChildControl("title").setValue(title);
        this._showChildControl("content");
        var buttonContainer = this._showChildControl("buttons");

        this.__createButtons(buttonContainer, buttons);
      },

      /**
       * Creates buttons in UI
       *
       * @param buttonContainer {unify.ui.core.Widget} Container to add buttons to
       * @param buttons {Array} Array of button configurations to add to buttonContainer
       */
      __createButtons : function(buttonContainer, buttons) {
        var leftButtonContainer_layout = new unify.ui.layout.HBox();
        leftButtonContainer_layout.setAlignX("left");
        leftButtonContainer_layout.setSpacing(10);
        var leftButtonContainer = new unify.ui.container.Composite(leftButtonContainer_layout);

        var centerButtonContainer_layout = new unify.ui.layout.HBox();
        centerButtonContainer_layout.setAlignX("center");
        centerButtonContainer_layout.setSpacing(10);
        var centerButtonContainer = new unify.ui.container.Composite(centerButtonContainer_layout);

        var rightButtonContainer_layout = new unify.ui.layout.HBox();
        rightButtonContainer_layout.setAlignX("right");
        rightButtonContainer_layout.setSpacing(10);
        var rightButtonContainer = new unify.ui.container.Composite(rightButtonContainer_layout);

        buttonContainer.add(leftButtonContainer, {flex: 2});
        buttonContainer.add(centerButtonContainer, {flex: 1});
        buttonContainer.add(rightButtonContainer, {flex: 2});

        if (!buttons || (buttons.length <= 0)) {
          // No buttons are specified. Create a default Button

          var okBtn = this.__okBtn = new unify.ui.form.Button("OK");
          okBtn.setAppearance("dialog.button");
          okBtn.set({
            allowGrowX: true,
            allowGrowY: false,
            alignY: "middle"
          });

          okBtn.addListener("execute", function() {
            this.fireDataEvent("execute", BTN_OK);
          }, this);

          centerButtonContainer.add(okBtn);

        } else  {
          // generate buttons

          var btnCount = buttons.length;

          if (btnCount > 4) {
            this.warn("Too much buttons. Maximal 4 buttons are supported.");
            btnCount = 4;
          }

          for (var i=0; i<btnCount; i++) {
            var button = buttons[i];

            //error handling
            if (!button.label) {
              this.warn("Button #"+i+" has no label.");
              continue;
            }
            if (!button.id) {
              this.warn("Button #"+i+" has no id.");
              continue;
            }
            if (!button.align) {
              this.warn("Button #"+i+" has no align. Using default align");
              button.align = "right";
            }

            // create new button
            var userBtn = new unify.ui.form.Button(button.label);
            userBtn.setUserData("id", button.id);
            userBtn.setAppearance("dialog.button");
            userBtn.set({
              allowGrowX: true,
              allowGrowY: false,
              alignY: "middle"
            });

            userBtn.addListener("execute", this.__onButtonExecute, this);

            // add the new button to the right alignment container
            switch (button.align.toUpperCase()) {
              case "LEFT":
                leftButtonContainer.add(userBtn);
                break;
              case "CENTER":
                centerButtonContainer.add(userBtn);
                break;
              default:
                this.warn("Button #"+i+": align \""+button.align+"\" is invalid. Using default align");
              case "RIGHT":
                rightButtonContainer.add(userBtn);
            }

          }
        }

        return buttonContainer;
      },

      /**
       * Handler for tap on buttons
       * @param e {qx.event.type.Event} Event
       */
      __onButtonExecute : function(e) {
        this.fireDataEvent("execute", e.getTarget().getUserData("id"));
      }

    }
  });

})();<commit_msg>Refactor dialog to use lowland event system<commit_after>/* ***********************************************************************************************

    Unify Project

    Homepage: unify-project.org
    License: MIT + Apache (V2)
    Copyright: 2012 Deutsche Telekom AG, Germany, http://telekom.com

*********************************************************************************************** */

(function() {

  /**
   * The ID of the CLOSE button. (The one in the right upper corner)
   */
  var BTN_CLOSE = "CLOSE";

  /**
   * The ID of the default OK button
   */
  var BTN_OK = "OK";

  /**
   * Generic modular dialog
   */
  core.Class("unify.ui.dialog.GenericDialog", {
    include: [
              unify.ui.container.Composite,
              unify.ui.core.MChildControl,
              unify.ui.core.MRemoteChildrenHandling
             ],
    implement : [unify.ui.core.IPopOver],

    /*
     *****************************************************************************
       EVENTS
     *****************************************************************************
     */

    events: {
      /** This event is fired when the dialog is closed by pressing a button */
      "execute": lowland.events.DataEvent
    },

    /**
     * Creates a new generic dialog
     *
     * @param title {String} Title of dialog
     * @param buttons {Array} Array of buttons
     */
    construct: function(title, buttons) {
      unify.ui.container.Composite.call(this, new unify.ui.layout.VBox());
      unify.ui.core.MChildControl.call(this);
      unify.ui.core.MRemoteChildrenHandling.call(this);

      this.__createUI(title, buttons);
    },

    /*
     *****************************************************************************
       PROPERTIES
     *****************************************************************************
     */
    properties : {
      // overridden
      appearance : {
        init: "dialog"
      }
    },

    /*
     *****************************************************************************
       MEMBERS
     *****************************************************************************
     */
    members : {

      // TODO:
      indexOf : function() {
        return unify.ui.core.MRemoteChildrenHandling.prototype.indexOf.apply(this, arguments);
      },
      add : function() {
        unify.ui.core.MRemoteChildrenHandling.prototype.add.apply(this, arguments);
      },
      getChildren : function() {
        return unify.ui.core.MRemoteChildrenHandling.prototype.getChildren.apply(this, arguments);
      },
      setStyle : function() {
        unify.ui.core.MRemoteChildrenHandling.prototype.setStyle.apply(this, arguments);
      },
      // TODO DONE

      getModal : function() {
        return true;
      },

      /**
       * Get children container that is accessed via remote child handling
       *
       * @return {unify.ui.core.Widget} Container
       */
      getChildrenContainer : function() {
        return this.getChildControl("content");
      },

      /**
       * Creates child controls
       *
       * @param id {String} ID of control
       * @return {unify.ui.core.Widget} Widget
       */
      _createChildControlImpl : function(id) {
        var control;

        if (id == "X") {
          // close button (right upper corner)
          control = new unify.ui.form.Button("Close");
          this._add(control);
        } else if (id == "title") {
          control = new unify.ui.basic.Label();
          control.set({
            alignX: "center",
            alignY: "bottom"
          });
          this._add(control);
        } else if (id == "content") {
          control = new unify.ui.container.Composite(new unify.ui.layout.VBox());
          control.set({
            allowGrowX: true,
            allowGrowY: true,
            allowShrinkX: true,
            allowShrinkY: true
          });
          this._add(control, { flex: 1 });
        } else if (id == "buttons") {
          control = new unify.ui.container.Composite(new unify.ui.layout.HBox(10));
          control.set({
            allowGrowX: true,
            allowGrowY: false,
            allowShrinkX: true,
            allowShrinkY: false
          });
          this._add(control);
        }

        return control; // || this.base(arguments, id);
      },

      /**
       * Creates UI
       *
       * @param title {String} Title of UI
       * @param buttons {Array} Array of buttons to show
       */
      __createUI : function(title, buttons) {
        var X = this._showChildControl("X");
        X.addListener("execute", this.__onButtonExecute, this);
        X.setUserData("id", BTN_CLOSE);

        this._showChildControl("title").setValue(title);
        this._showChildControl("content");
        var buttonContainer = this._showChildControl("buttons");

        this.__createButtons(buttonContainer, buttons);
      },

      /**
       * Creates buttons in UI
       *
       * @param buttonContainer {unify.ui.core.Widget} Container to add buttons to
       * @param buttons {Array} Array of button configurations to add to buttonContainer
       */
      __createButtons : function(buttonContainer, buttons) {
        var leftButtonContainer_layout = new unify.ui.layout.HBox();
        leftButtonContainer_layout.setAlignX("left");
        leftButtonContainer_layout.setSpacing(10);
        var leftButtonContainer = new unify.ui.container.Composite(leftButtonContainer_layout);

        var centerButtonContainer_layout = new unify.ui.layout.HBox();
        centerButtonContainer_layout.setAlignX("center");
        centerButtonContainer_layout.setSpacing(10);
        var centerButtonContainer = new unify.ui.container.Composite(centerButtonContainer_layout);

        var rightButtonContainer_layout = new unify.ui.layout.HBox();
        rightButtonContainer_layout.setAlignX("right");
        rightButtonContainer_layout.setSpacing(10);
        var rightButtonContainer = new unify.ui.container.Composite(rightButtonContainer_layout);

        buttonContainer.add(leftButtonContainer, {flex: 2});
        buttonContainer.add(centerButtonContainer, {flex: 1});
        buttonContainer.add(rightButtonContainer, {flex: 2});

        if (!buttons || (buttons.length <= 0)) {
          // No buttons are specified. Create a default Button

          var okBtn = this.__okBtn = new unify.ui.form.Button("OK");
          okBtn.setAppearance("dialog.button");
          okBtn.set({
            allowGrowX: true,
            allowGrowY: false,
            alignY: "middle"
          });

          okBtn.addListener("execute", function() {
            this.fireEvent("execute", BTN_OK);
          }, this);

          centerButtonContainer.add(okBtn);

        } else  {
          // generate buttons

          var btnCount = buttons.length;

          if (btnCount > 4) {
            this.warn("Too much buttons. Maximal 4 buttons are supported.");
            btnCount = 4;
          }

          for (var i=0; i<btnCount; i++) {
            var button = buttons[i];

            //error handling
            if (!button.label) {
              this.warn("Button #"+i+" has no label.");
              continue;
            }
            if (!button.id) {
              this.warn("Button #"+i+" has no id.");
              continue;
            }
            if (!button.align) {
              this.warn("Button #"+i+" has no align. Using default align");
              button.align = "right";
            }

            // create new button
            var userBtn = new unify.ui.form.Button(button.label);
            userBtn.setUserData("id", button.id);
            userBtn.setAppearance("dialog.button");
            userBtn.set({
              allowGrowX: true,
              allowGrowY: false,
              alignY: "middle"
            });

            userBtn.addListener("execute", this.__onButtonExecute, this);

            // add the new button to the right alignment container
            switch (button.align.toUpperCase()) {
              case "LEFT":
                leftButtonContainer.add(userBtn);
                break;
              case "CENTER":
                centerButtonContainer.add(userBtn);
                break;
              default:
                this.warn("Button #"+i+": align \""+button.align+"\" is invalid. Using default align");
              case "RIGHT":
                rightButtonContainer.add(userBtn);
            }

          }
        }

        return buttonContainer;
      },

      /**
       * Handler for tap on buttons
       * @param e {qx.event.type.Event} Event
       */
      __onButtonExecute : function(e) {
        this.fireEvent("execute", e.getTarget().getUserData("id"));
      }

    }
  });

})();<|endoftext|>


<commit_before>import ShoppingListCache from '../cache/ShoppingListCache';

const CACHE_VERSION = 9;
const URLS_TO_CACHE = [
    '/',
    '/index.html',
    '/sw.js',
    '/manifest.json',
    '/style/fonts/roboto_100_italic_latin-ext.woff2',
    '/style/fonts/roboto_300_italic_latin-ext.woff2',
    '/style/fonts/roboto_400_italic_latin-ext.woff2',
    '/style/fonts/roboto_500_italic_latin-ext.woff2',
    '/style/fonts/roboto_700_italic_latin-ext.woff2',
    '/style/fonts/roboto_900_italic_latin-ext.woff2',
    '/style/fonts/roboto_100_italic_latin.woff2',
    '/style/fonts/roboto_300_italic_latin.woff2',
    '/style/fonts/roboto_400_italic_latin.woff2',
    '/style/fonts/roboto_500_italic_latin.woff2',
    '/style/fonts/roboto_700_italic_latin.woff2',
    '/style/fonts/roboto_900_italic_latin.woff2',
    '/style/fonts/roboto_100_normal_latin-ext.woff2',
    '/style/fonts/roboto_300_normal_latin-ext.woff2',
    '/style/fonts/roboto_400_normal_latin-ext.woff2',
    '/style/fonts/roboto_500_normal_latin-ext.woff2',
    '/style/fonts/roboto_700_normal_latin-ext.woff2',
    '/style/fonts/roboto_900_normal_latin-ext.woff2',
    '/style/fonts/roboto_100_normal_latin.woff2',
    '/style/fonts/roboto_300_normal_latin.woff2',
    '/style/fonts/roboto_400_normal_latin.woff2',
    '/style/fonts/roboto_500_normal_latin.woff2',
    '/style/fonts/roboto_700_normal_latin.woff2',
    '/style/fonts/roboto_900_normal_latin.woff2',
    '/templates/authentication/login/login.html',
    '/templates/navigation/navigation.html',
    '/templates/navigation/navMenu/navMenu.html',
    '/templates/navigation/leftSideNav/leftSideNav.html',
    '/templates/user/delete/userDelete.html',
    '/templates/user/edit/userData.html',
    '/templates/lists/list.html',
    '/templates/lists/lists.html',
    '/templates/lists/view/view.html',
    '/templates/lists/view/emptyList.html',
    '/templates/lists/new/newList.html',
    '/templates/lists/edit/editList.html',
    '/templates/directives/loadingCycle.html',
    '/templates/authentication/register/register.html',
    '/templates/authentication/register/confirmation/confirmationNotification.html',
    '/templates/authentication/register/confirmation/confirmation.html',
    '/templates/item/new/newItem.html',
    '/templates/item/item.html',
    '/templates/article/article.html',
    '/templates/article/dictionary/dictionary.html',
    '/templates/article/dictionary/emptyDictionary.html',
    '/style/css/app-compact.css',
    '/js/ShoppingList.min.js',
    '/img/icons/action/ic_add_shopping_cart_24px.svg',
    '/img/icons/action/ic_lock_outline_24px.svg',
    '/img/icons/action/ic_shopping_cart_24px.svg',
    '/img/icons/action/ic_delete_24px.svg',
    '/img/icons/action/ic_settings_24px.svg',
    '/img/icons/action/ic_list_24px.svg',
    '/img/icons/action/ic_search_24px.svg',
    '/img/icons/action/ic_chrome_reader_mode_24px.svg',
    '/img/icons/communication/ic_email_24px.svg',
    '/img/icons/communication/ic_vpn_key_24px.svg',
    '/img/icons/communication/ic_clear_all_24px.svg',
    '/img/icons/content/ic_remove_circle_24px.svg',
    '/img/icons/content/ic_save_24px.svg',
    '/img/icons/hardware/ic_keyboard_arrow_left_24px.svg',
    '/img/icons/navigation/ic_menu_24px.svg',
    '/img/icons/navigation/ic_more_vert_24px.svg',
    '/img/icons/navigation/ic_refresh_24px.svg',
    '/img/icons/navigation/ic_close_24px.svg',
    '/img/icons/navigation/ic_arrow_back_24px.svg',
    '/img/icons/notification/ic_sync_24px.svg',
    '/img/icons/notification/ic_sync_disabled_24px.svg',
    '/img/icons/notification/ic_sync_problem_24px.svg',
    '/img/icons/social/ic_mood_bad_48px.svg',
    '/img/icons/social/ic_person_24px.svg',
    '/img/icons/social/ic_person_add_24px.svg',
    '/img/icons/Toggle/ic_check_box_24px.svg',
    '/img/icons/Toggle/ic_check_box_outline_blank_24px.svg'
];

const shoppingListCache = new ShoppingListCache(self, CACHE_VERSION, URLS_TO_CACHE);

shoppingListCache.initListeners();<commit_msg>Update to cache Version 10<commit_after>import ShoppingListCache from '../cache/ShoppingListCache';

const CACHE_VERSION = 10;
const URLS_TO_CACHE = [
    '/',
    '/index.html',
    '/sw.js',
    '/manifest.json',
    '/style/fonts/roboto_100_italic_latin-ext.woff2',
    '/style/fonts/roboto_300_italic_latin-ext.woff2',
    '/style/fonts/roboto_400_italic_latin-ext.woff2',
    '/style/fonts/roboto_500_italic_latin-ext.woff2',
    '/style/fonts/roboto_700_italic_latin-ext.woff2',
    '/style/fonts/roboto_900_italic_latin-ext.woff2',
    '/style/fonts/roboto_100_italic_latin.woff2',
    '/style/fonts/roboto_300_italic_latin.woff2',
    '/style/fonts/roboto_400_italic_latin.woff2',
    '/style/fonts/roboto_500_italic_latin.woff2',
    '/style/fonts/roboto_700_italic_latin.woff2',
    '/style/fonts/roboto_900_italic_latin.woff2',
    '/style/fonts/roboto_100_normal_latin-ext.woff2',
    '/style/fonts/roboto_300_normal_latin-ext.woff2',
    '/style/fonts/roboto_400_normal_latin-ext.woff2',
    '/style/fonts/roboto_500_normal_latin-ext.woff2',
    '/style/fonts/roboto_700_normal_latin-ext.woff2',
    '/style/fonts/roboto_900_normal_latin-ext.woff2',
    '/style/fonts/roboto_100_normal_latin.woff2',
    '/style/fonts/roboto_300_normal_latin.woff2',
    '/style/fonts/roboto_400_normal_latin.woff2',
    '/style/fonts/roboto_500_normal_latin.woff2',
    '/style/fonts/roboto_700_normal_latin.woff2',
    '/style/fonts/roboto_900_normal_latin.woff2',
    '/templates/authentication/login/login.html',
    '/templates/navigation/navigation.html',
    '/templates/navigation/navMenu/navMenu.html',
    '/templates/navigation/leftSideNav/leftSideNav.html',
    '/templates/user/delete/userDelete.html',
    '/templates/user/edit/userData.html',
    '/templates/lists/list.html',
    '/templates/lists/lists.html',
    '/templates/lists/view/view.html',
    '/templates/lists/view/emptyList.html',
    '/templates/lists/new/newList.html',
    '/templates/lists/edit/editList.html',
    '/templates/directives/loadingCycle.html',
    '/templates/authentication/register/register.html',
    '/templates/authentication/register/confirmation/confirmationNotification.html',
    '/templates/authentication/register/confirmation/confirmation.html',
    '/templates/item/new/newItem.html',
    '/templates/item/item.html',
    '/templates/article/article.html',
    '/templates/article/dictionary/dictionary.html',
    '/templates/article/dictionary/emptyDictionary.html',
    '/style/css/app-compact.css',
    '/js/ShoppingList.min.js',
    '/img/icons/action/ic_add_shopping_cart_24px.svg',
    '/img/icons/action/ic_lock_outline_24px.svg',
    '/img/icons/action/ic_shopping_cart_24px.svg',
    '/img/icons/action/ic_delete_24px.svg',
    '/img/icons/action/ic_settings_24px.svg',
    '/img/icons/action/ic_list_24px.svg',
    '/img/icons/action/ic_search_24px.svg',
    '/img/icons/action/ic_chrome_reader_mode_24px.svg',
    '/img/icons/communication/ic_email_24px.svg',
    '/img/icons/communication/ic_vpn_key_24px.svg',
    '/img/icons/communication/ic_clear_all_24px.svg',
    '/img/icons/content/ic_remove_circle_24px.svg',
    '/img/icons/content/ic_save_24px.svg',
    '/img/icons/hardware/ic_keyboard_arrow_left_24px.svg',
    '/img/icons/navigation/ic_menu_24px.svg',
    '/img/icons/navigation/ic_more_vert_24px.svg',
    '/img/icons/navigation/ic_refresh_24px.svg',
    '/img/icons/navigation/ic_close_24px.svg',
    '/img/icons/navigation/ic_arrow_back_24px.svg',
    '/img/icons/notification/ic_sync_24px.svg',
    '/img/icons/notification/ic_sync_disabled_24px.svg',
    '/img/icons/notification/ic_sync_problem_24px.svg',
    '/img/icons/social/ic_mood_bad_48px.svg',
    '/img/icons/social/ic_person_24px.svg',
    '/img/icons/social/ic_person_add_24px.svg',
    '/img/icons/Toggle/ic_check_box_24px.svg',
    '/img/icons/Toggle/ic_check_box_outline_blank_24px.svg'
];

const shoppingListCache = new ShoppingListCache(self, CACHE_VERSION, URLS_TO_CACHE);

shoppingListCache.initListeners();<|endoftext|>


<commit_before>var Step = require('step'),
    fs = require('fs'),
    path = require('path'),
    exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    settings = Bones.plugin.config;

// @TODO: need a queue system. Difficult to manage atm because process
// completion is now determined outside this process.
// See http://en.wikipedia.org/wiki/SIGCHLD ... may be useful for determining
// when a child process has died and can be removed from the pool.
var start = function(model, data, callback) {
    if (data.status === 'waiting') {
        var args = [];
        // tilemill index.js
        args.push(path.resolve(path.join(__dirname + '/../index.js')));
        // export command
        args.push('export');
        // datasource
        args.push(data.project);
        // filepath
        args.push(path.join(settings.files, 'export', data.filename));
        // url, @TODO: need proper host info.
        args.push('--url=' + 'http://localhost:'+settings.port+'/api/Export/'+data.id);

        if (data.bbox) args.push('--bbox=' + data.bbox.join(','));
        if (data.width) args.push('--width=' + data.width);
        if (data.height) args.push('--height=' + data.height);
        if (data.minzoom) args.push('--minzoom=' + data.minzoom);
        if (data.maxzoom) args.push('--maxzoom=' + data.maxzoom);

        var child = spawn(process.execPath, args);
        model.set({pid:child.pid, status:'processing'});
        Backbone.sync('update', model, callback, callback);
    } else if (data.status === 'processing') {
        var pid = data.pid || 0;
        exec('ps -p ' + pid + ' | grep ' + pid, function(err, stdout) {
            if (!err) return callback();
            model.set({status: 'error', error: 'Export process died.'});
            Backbone.sync('update', model, callback, callback);
        });
    } else {
        callback();
    }
};

models.Export.prototype.sync = function(method, model, success, error) {
    switch (method) {
    // Export child processes are managed from the parent:
    // 1. when an export model is first created a process is started.
    // 2. when reading models the process health is checked.
    case 'read':
    case 'create':
        Backbone.sync(method, model, function(data) {
            start(model, model.toJSON(), function() {
                success(data);
            });
        }, error);
        break;
    // Updates occur via the child process.
    case 'update':
        Backbone.sync(method, model, success, error);
        break;
    // Deletion kills the child process and removes the export file if it
    // exists. Note that SIGUSR1 is used instead of SIGINT for two reasons:
    // 1. The child process does not exit directly on SIGINT to prevent it
    //    from going down if the parent goes down.
    // 2. If the model `pid` is stale and somehow the `pid` is now occupied
    //    by another process SIGUSR1 likely won't kill the process.
    case 'delete':
        Step(function() {
            Backbone.sync('read', model, this, this);
        },
        function(data) {
            if (data && data.pid) {
                // Try/catch as process may not exist.
                try { process.kill(data.pid, 'SIGUSR1'); }
                catch(err) {}
            }
            if (data && data.filename) {
                var filepath = path.join(settings['export'], data.filename);
                path.exists(filepath, function(exists) {
                    if (exists) return fs.unlink(filepath, this);
                    this();
                }.bind(this));
            } else {
                this();
            }
        },
        function(err) {
            Backbone.sync(method, model, success, error);
        });
        break;
    }
};

models.Exports.prototype.sync = function(method, model, success, error) {
    if (method !== 'read') return success({});
    Backbone.sync(method, model, function(data) {
        Step(function() {
            var group = this.group();
            _(data).each(function(m) {
                var model = new models.Export(m);
                start(model, model.toJSON(), group());
            });
        }, function() {
            success(data);
        });
    }, error);
};
<commit_msg>Nice the export processes.<commit_after>var Step = require('step'),
    fs = require('fs'),
    path = require('path'),
    exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    settings = Bones.plugin.config;

// @TODO: need a queue system. Difficult to manage atm because process
// completion is now determined outside this process.
// See http://en.wikipedia.org/wiki/SIGCHLD ... may be useful for determining
// when a child process has died and can be removed from the pool.
var start = function(model, data, callback) {
    if (data.status === 'waiting') {
        var args = [];
        // nice the export process.
        args.push('-n19');
        // path to node bin.
        args.push(process.execPath);
        // tilemill index.js
        args.push(path.resolve(path.join(__dirname + '/../index.js')));
        // export command
        args.push('export');
        // datasource
        args.push(data.project);
        // filepath
        args.push(path.join(settings.files, 'export', data.filename));
        // url, @TODO: need proper host info.
        args.push('--url=' + 'http://localhost:'+settings.port+'/api/Export/'+data.id);

        if (data.bbox) args.push('--bbox=' + data.bbox.join(','));
        if (data.width) args.push('--width=' + data.width);
        if (data.height) args.push('--height=' + data.height);
        if (data.minzoom) args.push('--minzoom=' + data.minzoom);
        if (data.maxzoom) args.push('--maxzoom=' + data.maxzoom);

        var child = spawn('nice', args);
        model.set({pid:child.pid, status:'processing'});
        Backbone.sync('update', model, callback, callback);
    } else if (data.status === 'processing') {
        var pid = data.pid || 0;
        exec('ps -p ' + pid + ' | grep ' + pid, function(err, stdout) {
            if (!err) return callback();
            model.set({status: 'error', error: 'Export process died.'});
            Backbone.sync('update', model, callback, callback);
        });
    } else {
        callback();
    }
};

models.Export.prototype.sync = function(method, model, success, error) {
    switch (method) {
    // Export child processes are managed from the parent:
    // 1. when an export model is first created a process is started.
    // 2. when reading models the process health is checked.
    case 'read':
    case 'create':
        Backbone.sync(method, model, function(data) {
            start(model, model.toJSON(), function() {
                success(data);
            });
        }, error);
        break;
    // Updates occur via the child process.
    case 'update':
        Backbone.sync(method, model, success, error);
        break;
    // Deletion kills the child process and removes the export file if it
    // exists. Note that SIGUSR1 is used instead of SIGINT for two reasons:
    // 1. The child process does not exit directly on SIGINT to prevent it
    //    from going down if the parent goes down.
    // 2. If the model `pid` is stale and somehow the `pid` is now occupied
    //    by another process SIGUSR1 likely won't kill the process.
    case 'delete':
        Step(function() {
            Backbone.sync('read', model, this, this);
        },
        function(data) {
            if (data && data.pid) {
                // Try/catch as process may not exist.
                try { process.kill(data.pid, 'SIGUSR1'); }
                catch(err) {}
            }
            if (data && data.filename) {
                var filepath = path.join(settings['export'], data.filename);
                path.exists(filepath, function(exists) {
                    if (exists) return fs.unlink(filepath, this);
                    this();
                }.bind(this));
            } else {
                this();
            }
        },
        function(err) {
            Backbone.sync(method, model, success, error);
        });
        break;
    }
};

models.Exports.prototype.sync = function(method, model, success, error) {
    if (method !== 'read') return success({});
    Backbone.sync(method, model, function(data) {
        Step(function() {
            var group = this.group();
            _(data).each(function(m) {
                var model = new models.Export(m);
                start(model, model.toJSON(), group());
            });
        }, function() {
            success(data);
        });
    }, error);
};
<|endoftext|>


<commit_before>angular.module('baseapolo')
    .config(
        function ($stateProvider, $urlRouterProvider, $locationProvider, $urlMatcherFactoryProvider, authProvider) {
            console.log("login route");

            var url = '/login';

            $urlRouterProvider.when(url, function($state) {
                // If the user is authenticated, redirect to home
                if (authProvider.isLoggedIn()) {
                    $state.transitionTo('root.home');
                    return true;
                }
                return false;
            });

            $stateProvider
                .state('root.login', {
                    url: url,
                    views: {
                        '@': {
                            templateUrl: './app/components/login/views/login.html'
                        },
                        'footer@': {
                            template: ''
                        }
                    }
                })
        });
<commit_msg>Fixed login route<commit_after>angular.module('baseapolo')
    .config(
        function ($stateProvider, $urlRouterProvider, $locationProvider, $urlMatcherFactoryProvider, authProvider) {
            console.log("login route");

            var url = '/login';

            $urlRouterProvider.when(url, function($state) {
                // If the user is authenticated, redirect to home
                if (authProvider.isAuthenticated()) {
                    $state.transitionTo('root.home');
                    return true;
                }
                return false;
            });

            $stateProvider
                .state('root.login', {
                    url: url,
                    views: {
                        '@': {
                            templateUrl: './app/components/login/views/login.html'
                        },
                        'footer@': {
                            template: ''
                        }
                    }
                })
        });
<|endoftext|>


<commit_before>
var app = app || {};

(function (hex) { // jshint ignore: line
Colors = (function () { // jshint ignore: line

    // Some color constants
    var DISABLED_COLOR = '#aaaaaa',
        COLOR_BINARY_OFF = '#444444',       // binary attr off
        COLOR_BINARY_ON = '#FFFF00',        // binary attr on
        COLOR_BINARY_BOTH_ON = '#00FF00',   // binary both attrs on
        COLOR_BINARY_SECOND_ON = '#0000FF'; // binary second attr on

    // The color to use as hexagon fill, depending on the background color
    var NO_DATA_LIGHT_BG = '#c0c0c0',
        NO_DATA_DARK_BG = '#333333',
        badValue = false, // The current category input has a bad value
        $link;

    var $form,
        dialogHex;

    // Define the colormap template helper, at this scope for some reason
    Template.colormapT.helpers({

        // Use the Session version of the colormap
        colorArray: function () {
            // TODO this should be a local reactiveVar rather than a global
            // session var
            var colorArray = Session.get('colorArray');
            return colorArray;
        }
    });

    // Define the background color template helper
    Template.navBarT.helpers({

        background: function () {
            if (Session.get('background') === 'black') {
                return 'White';
            } else {
                return 'Black';
            }
        }
    });

    function findRowLayer ($row, colorArray) {

        // Find the layer in the colorArray from a row element
        var layerName = $row.find('td:first').attr('title');
        return _.find(colorArray, function (layer) {
            return (layer.name === layerName);
        });
    }

    function findColumnCat ($input, colorArray) {

        // Find the category in the colorArray from an input element
        var layer = findRowLayer($input.parents('tr'), colorArray),
            $el = $input.parent().prev(),
            catName = $.trim(($el).text());

        // Trim and remove the trailing colon
        catName = catName.slice(0, catName.length - 1);

        // Return the wanted category
        return _.find(layer.cats, function (cat) {
            return (cat.name === catName);
        });
    }

    // Convert an rgb array, [66, 77, 88], to an object, {r:66, b:77, g:88}
    function rgbArrayToObj (arr) {
        return new Color({r: arr[0], g: arr[1], b: arr[2]});
    }

    function setCatAttrs (a) {

        // Set category input attributes that may change with user edits.
        if (rgbArrayToObj(a.operVal).dark()) {
            a.dark = 'dark';
        } else {
            a.dark = '';
        }
        if (a.operVal === a.fileVal) {
            a.isFileVal = 'isFileVal';
        } else {
            a.isFileVal = '';
        }
    }

    function updateColormap (aCat) {

        // Update the colormap, then redraw the hexmap
        var layer = aCat.layer,
            catI;

        _.find(colormaps[layer], function (cat, i) {
            if (cat.name === aCat.name) {
                catI = i;
                return true;
            }
            return false;
        });
        colormaps[layer][catI].color = new Color(aCat.operVal);
        refreshColors();
    }

    function rowClick(ev) {

        // Fires when a row is clicked.
        // Highlights the clicked row to make it easier for the user
        // to follow across all of the categories for this layer.
        var $t = $(ev.currentTarget),

            // Clear the 'selected' attribute of all layers
            colorArray = _.map(Session.get('colorArray'), function (layer) {
                var l = _.clone(layer);
                l.selected = '';
                return l;
            }),
            // Find the current layer in the color array
            selected = findRowLayer($t, colorArray);
        selected.selected = 'selected';
        Session.set('colorArray', colorArray);
    }

    function inputBlur (ev) {

        // Fires when a color input field loses focus.
        // Update its properties & the map
        var $t = $(ev.currentTarget),
            colorArray = Session.get('colorArray'),
            cat = findColumnCat($t, colorArray),
            newVal = $t.prop('value').trim().toUpperCase();

        if (cat.shaking === 'shaking') {

            // nothing to do when the input box is shaking
            return;
        }
        if (!newVal.match(/^#([A-F0-9]{6})$/)) {

            // An invalid hex string, so set the Session to shake then
            // set the Session to not shake and put the focus back to this
            cat.shaking = 'shaking';
            Session.set('colorArray', colorArray);
            badValue = true;
            $t.effect('shake', null, null, function () {
                cat.shaking = '';
                Session.set('colorArray', colorArray);
                $t.focus();
            });
            return;
        }
        $t.prop('value', newVal); // clean up the input box value
        if (newVal !== cat.operVal) {

            // The new value is not the same as the operating color,
            // so update the operating color & update the colormap
            cat.operVal = newVal;
            setCatAttrs(cat);
            Session.set('colorArray', colorArray);
            Meteor.flush();
            updateColormap(cat);
            badValue = false;
        }
    }

    function inputKeyup (ev) {

        // Fires when a key is released in a color input field
        var $t = $(ev.currentTarget),
            newVal = $t.prop('value').trim(),
            colorArray,
            cat;

        if (newVal === '') {

            // The textbox is empty so display the file color string
            // so the user will know what that is
            colorArray = Session.get('colorArray');
            cat = findColumnCat($t, colorArray);
            $t.prop('value', cat.fileVal);
        }
        if (ev.which === 13) {

            // This is the return key, so trigger a blur event
            $t.parent().next().next().find('input').focus();
        }
    }

    function makeTsv($link) {

        // The download button has been pushed
        var tsv = '';

        Object.keys(colormaps).forEach(function (layer) {
            tsv += layer;
            _.each(colormaps[layer], function (cat, catIndex) {

                // If the colormap entry is not empty...
                if (Object.keys(colormaps[layer]).length > 0) {
                    tsv += '\t' + catIndex + '\t' + cat.name + '\t' +
                        cat.color.hexString();
                }
            });
            tsv += '\n';
        });

        // Fill in the data URI for saving. We use the handy
        // window.bota encoding function.
        $link.attr("href", "data:text/plain;base64," +
            window.btoa(tsv));

        $link[0].click();
    }

    function render() {
        Session.set('colorArray', Colors.colormapsToColorArray());
        $form
            .append($link)
            .on('click', 'tr', rowClick)
            .on('blur', 'input', inputBlur)
            .on('keyup', 'input', inputKeyup);
    }

    return { // Public methods

        disabled_color: function () {
            return DISABLED_COLOR;
        },

        binary_off: function () {
            return COLOR_BINARY_OFF;
        },

        binary_on: function () {
            return COLOR_BINARY_ON;
        },

        binary_both_on: function () {
            return COLOR_BINARY_BOTH_ON;
        },

        binary_second_on: function () {
            return COLOR_BINARY_SECOND_ON;
        },

        noDataColor: function () {
            return (Session.equals('background', 'white')) ?
                NO_DATA_LIGHT_BG : NO_DATA_DARK_BG;
        },

        colormapToState: function (colorVals) {

            // Convert one attr colormap into a form that state can save.
            var cats = _.map(colorVals, function(val) {
                    return val.name;

                }),
                colors = _.map(colorVals, function(val) {
                    return val.color.hexString();
                });
            return {cats: cats, colors: colors};
        },

        colormapToColorArray: function (layerVal, layerKey) {

            // Convert one attr colormap colors into a form that templates
            // can use.
            var cats = _.map(layerVal, function(val) {
                var cat = {
                        name: val.name,
                        fileVal: rgbArrayToObj(
                            val.fileColor.values.rgb).hexString(),
                        operVal: val.color.hexString(),
                        layer: layerKey,
                    };
                setCatAttrs(cat);
                return cat;
            });
            return {name: layerKey, cats: cats, selected: ''};
        },

        colormapsToColorArray: function() {

            // Convert the colormaps into a form the template can use,
            // filtering out any entries with no categories.
            return _.filter(
                _.map(colormaps, Colors.colormapToColorArray),
                function (entry) {
                    return (entry.cats.length > 0);
                }
            );
        },

        init: function () {
            var $button = $('#navBar .colormap');
            $form = $('#colorMapDiv');
            $link = $('#colorMapDiv a');

            $('#background').on('click', function () {
                if (Session.equals('background', 'white')) {
                    Session.set('background', 'black');
                } else {
                    Session.set('background', 'white');
                }
                // The background change requires a new map to show the
                // background.
                createMap();
                createHexagons(true);
                showOverlayNodes();
            });

            // Prepare to display a dialog
            var opts = {
                width: $(window).width() * 2 / 3,
                height: $(window).height() * 2 / 3,
                position: {my: 'left top', at: 'left top+50', of: window},
                buttons: [
                    {
                        text: 'Download',
                        click: function () {
                            if (!badValue) {
                                makeTsv($link);
                                $form.dialog('destroy');
                            }
                        }
                    }
                ],
            };
            var dialogHex = createDialogHex({
                $el: $form,
                opts: opts,
                showFx: render,
                helpAnchor: '/help/menus.html#colormap'
            });

            // Create a link from the navBar
            Tool.add("colormap", function () {
                dialogHex.show();
                Tool.activity(false);
            }, 'Change colors of attributes', 'mapShow');
        },
    };
}());
})(app);

<commit_msg>added default binary colormap function<commit_after>
var app = app || {};

(function (hex) { // jshint ignore: line
Colors = (function () { // jshint ignore: line

    // Some color constants
    var DISABLED_COLOR = '#aaaaaa',
        COLOR_BINARY_OFF = '#444444',       // binary attr off
        COLOR_BINARY_ON = '#FFFF00',        // binary attr on
        COLOR_BINARY_BOTH_ON = '#00FF00',   // binary both attrs on
        COLOR_BINARY_SECOND_ON = '#0000FF'; // binary second attr on

    // The color to use as hexagon fill, depending on the background color
    var NO_DATA_LIGHT_BG = '#c0c0c0',
        NO_DATA_DARK_BG = '#333333',
        badValue = false, // The current category input has a bad value
        $link;

    var $form,
        dialogHex;

    // Define the colormap template helper, at this scope for some reason
    Template.colormapT.helpers({

        // Use the Session version of the colormap
        colorArray: function () {
            // TODO this should be a local reactiveVar rather than a global
            // session var
            var colorArray = Session.get('colorArray');
            return colorArray;
        }
    });

    // Define the background color template helper
    Template.navBarT.helpers({

        background: function () {
            if (Session.get('background') === 'black') {
                return 'White';
            } else {
                return 'Black';
            }
        }
    });

    function findRowLayer ($row, colorArray) {

        // Find the layer in the colorArray from a row element
        var layerName = $row.find('td:first').attr('title');
        return _.find(colorArray, function (layer) {
            return (layer.name === layerName);
        });
    }

    function findColumnCat ($input, colorArray) {

        // Find the category in the colorArray from an input element
        var layer = findRowLayer($input.parents('tr'), colorArray),
            $el = $input.parent().prev(),
            catName = $.trim(($el).text());

        // Trim and remove the trailing colon
        catName = catName.slice(0, catName.length - 1);

        // Return the wanted category
        return _.find(layer.cats, function (cat) {
            return (cat.name === catName);
        });
    }

    // Convert an rgb array, [66, 77, 88], to an object, {r:66, b:77, g:88}
    function rgbArrayToObj (arr) {
        return new Color({r: arr[0], g: arr[1], b: arr[2]});
    }

    function setCatAttrs (a) {

        // Set category input attributes that may change with user edits.
        if (rgbArrayToObj(a.operVal).dark()) {
            a.dark = 'dark';
        } else {
            a.dark = '';
        }
        if (a.operVal === a.fileVal) {
            a.isFileVal = 'isFileVal';
        } else {
            a.isFileVal = '';
        }
    }

    function updateColormap (aCat) {
        // Update the colormap, then redraw the hexmap
        var layer = aCat.layer,
            catI;

        _.find(colormaps[layer], function (cat, i) {
            if (cat.name === aCat.name) {
                catI = i;
                return true;
            }
            return false;
        });
        colormaps[layer][catI].color = new Color(aCat.operVal);
        refreshColors();
    }

    function rowClick(ev) {

        // Fires when a row is clicked.
        // Highlights the clicked row to make it easier for the user
        // to follow across all of the categories for this layer.
        var $t = $(ev.currentTarget),

            // Clear the 'selected' attribute of all layers
            colorArray = _.map(Session.get('colorArray'), function (layer) {
                var l = _.clone(layer);
                l.selected = '';
                return l;
            }),
            // Find the current layer in the color array
            selected = findRowLayer($t, colorArray);
        selected.selected = 'selected';
        Session.set('colorArray', colorArray);
    }

    function inputBlur (ev) {
        // Fires when a color input field loses focus.
        // Update its properties & the map
        var $t = $(ev.currentTarget),
            colorArray = Session.get('colorArray'),
            cat = findColumnCat($t, colorArray),
            newVal = $t.prop('value').trim().toUpperCase();

        if (cat.shaking === 'shaking') {

            // nothing to do when the input box is shaking
            return;
        }
        if (!newVal.match(/^#([A-F0-9]{6})$/)) {

            // An invalid hex string, so set the Session to shake then
            // set the Session to not shake and put the focus back to this
            cat.shaking = 'shaking';
            Session.set('colorArray', colorArray);
            badValue = true;
            $t.effect('shake', null, null, function () {
                cat.shaking = '';
                Session.set('colorArray', colorArray);
                $t.focus();
            });
            return;
        }
        $t.prop('value', newVal); // clean up the input box value
        if (newVal !== cat.operVal) {

            // The new value is not the same as the operating color,
            // so update the operating color & update the colormap
            cat.operVal = newVal;
            setCatAttrs(cat);
            Session.set('colorArray', colorArray);
            Meteor.flush();
            updateColormap(cat);
            badValue = false;
        }
    }

    function inputKeyup (ev) {

        // Fires when a key is released in a color input field
        var $t = $(ev.currentTarget),
            newVal = $t.prop('value').trim(),
            colorArray,
            cat;

        if (newVal === '') {

            // The textbox is empty so display the file color string
            // so the user will know what that is
            colorArray = Session.get('colorArray');
            cat = findColumnCat($t, colorArray);
            $t.prop('value', cat.fileVal);
        }
        if (ev.which === 13) {

            // This is the return key, so trigger a blur event
            $t.parent().next().next().find('input').focus();
        }
    }

    function makeTsv($link) {

        // The download button has been pushed
        var tsv = '';

        Object.keys(colormaps).forEach(function (layer) {
            tsv += layer;
            _.each(colormaps[layer], function (cat, catIndex) {

                // If the colormap entry is not empty...
                if (Object.keys(colormaps[layer]).length > 0) {
                    tsv += '\t' + catIndex + '\t' + cat.name + '\t' +
                        cat.color.hexString();
                }
            });
            tsv += '\n';
        });

        // Fill in the data URI for saving. We use the handy
        // window.bota encoding function.
        $link.attr("href", "data:text/plain;base64," +
            window.btoa(tsv));

        $link[0].click();
    }

    function render() {
        Session.set('colorArray', Colors.colormapsToColorArray());
        $form
            .append($link)
            .on('click', 'tr', rowClick)
            .on('blur', 'input', inputBlur)
            .on('keyup', 'input', inputKeyup);
    }

    return { // Public methods

        disabled_color: function () {
            return DISABLED_COLOR;
        },

        binary_off: function () {
            return COLOR_BINARY_OFF;
        },

        binary_on: function () {
            return COLOR_BINARY_ON;
        },

        binary_both_on: function () {
            return COLOR_BINARY_BOTH_ON;
        },

        binary_second_on: function () {
            return COLOR_BINARY_SECOND_ON;
        },

        default_binary_colormap : function () {
            var default_binary_colormap = [
                {
                    "color": new Color(COLOR_BINARY_OFF),
                    "fileColor": new Color(COLOR_BINARY_OFF),
                    "name": "0",
                },
                {
                    "color": new Color(COLOR_BINARY_ON),
                    "fileColor": new Color(COLOR_BINARY_ON),
                    "name": "1",
                }
            ];
            return default_binary_colormap;
        },

        noDataColor: function () {
            return (Session.equals('background', 'white')) ?
                NO_DATA_LIGHT_BG : NO_DATA_DARK_BG;
        },

        colormapToState: function (colorVals) {

            // Convert one attr colormap into a form that state can save.
            var cats = _.map(colorVals, function(val) {
                    return val.name;

                }),
                colors = _.map(colorVals, function(val) {
                    return val.color.hexString();
                });
            return {cats: cats, colors: colors};
        },

        colormapToColorArray: function (layerVal, layerKey) {

            // Convert one attr colormap colors into a form that templates
            // can use.
            var cats = _.map(layerVal, function(val,i) {

                var cat = {
                        name:  val.name,
                        fileVal: rgbArrayToObj(
                            val.fileColor.values.rgb).hexString(),
                        operVal: val.color.hexString(),
                        layer: layerKey,
                    };
                setCatAttrs(cat);
                return cat;
            });
            return {name: layerKey, cats: cats, selected: ''};
        },

        colormapsToColorArray: function() {

            // Convert the colormaps into a form the template can use,
            // filtering out any entries with no categories.
            return _.filter(
                _.map(colormaps, Colors.colormapToColorArray),
                function (entry) {
                    return (entry.cats.length > 0);
                }
            );
        },

        init: function () {
            var $button = $('#navBar .colormap');
            $form = $('#colorMapDiv');
            $link = $('#colorMapDiv a');

            $('#background').on('click', function () {
                if (Session.equals('background', 'white')) {
                    Session.set('background', 'black');
                } else {
                    Session.set('background', 'white');
                }
                // The background change requires a new map to show the
                // background.
                createMap();
                createHexagons(true);
                showOverlayNodes();
            });

            // Prepare to display a dialog
            var opts = {
                width: $(window).width() * 2 / 3,
                height: $(window).height() * 2 / 3,
                position: {my: 'left top', at: 'left top+50', of: window},
                buttons: [
                    {
                        text: 'Download',
                        click: function () {
                            if (!badValue) {
                                makeTsv($link);
                                $form.dialog('destroy');
                            }
                        }
                    }
                ],
            };
            var dialogHex = createDialogHex({
                $el: $form,
                opts: opts,
                showFx: render,
                helpAnchor: '/help/menus.html#colormap'
            });

            // Create a link from the navBar
            Tool.add("colormap", function () {
                dialogHex.show();
                Tool.activity(false);
            }, 'Change colors of attributes', 'mapShow');
        },
    };
}());
})(app);

<|endoftext|>