<commit_before>'use strict';

const { concat } = require('lodash');
const copy = require('recursive-copy');
const path = require('path');

const cleanBuildDirectory = require('./cleanBuildDirectory');
const compose = require('./compose');
const events = require('./events');
const loadPatternGraph = require('./loadPatternGraph');
const logger = require('./log');
const PatternGraph = require('./pattern_graph').PatternGraph;
const CompileState = require('./object_factory').CompileState;
const processMetaPattern = require('./processMetaPattern');
const pe = require('./pattern_exporter');
const lh = require('./lineage_hunter');
const markModifiedPatterns = require('./markModifiedPatterns');
const parseAllLinks = require('./parseAllLinks');
const render = require('./render');
const Pattern = require('./object_factory').Pattern;

let fs = require('fs-extra'); // eslint-disable-line
let ui_builder = require('./ui_builder'); // eslint-disable-line
let copier = require('./copier'); // eslint-disable-line
let pattern_exporter = new pe(); // eslint-disable-line
let serve = require('./serve'); // eslint-disable-line

const lineage_hunter = new lh();

module.exports = (deletePatternDir, patternlab, additionalData) => {
  patternlab.events.emit(events.PATTERNLAB_BUILD_PATTERN_START, patternlab);

  const paths = patternlab.config.paths;

  //
  // CHECK INCREMENTAL BUILD GRAPH
  //
  const graph = (patternlab.graph = loadPatternGraph(
    patternlab,
    deletePatternDir
  ));
  const graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
  if (graphNeedsUpgrade) {
    logger.info(
      'Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. ' +
        'Incremental build is available again on the next successful run.'
    );

    // Ensure that the freshly built graph has the latest version again.
    patternlab.graph.upgradeVersion();
  }

  // Flags
  patternlab.incrementalBuildsEnabled = !(
    deletePatternDir || graphNeedsUpgrade
  );

  //
  // CLEAN BUILD DIRECTORY, maybe
  //
  return cleanBuildDirectory(
    patternlab.incrementalBuildsEnabled,
    patternlab
  ).then(() => {
    patternlab.buildGlobalData(additionalData);

    return patternlab
      .processAllPatternsIterative(paths.source.patterns)
      .then(() => {
        patternlab.events.emit(
          events.PATTERNLAB_PATTERN_ITERATION_END,
          patternlab
        );

        //now that all the main patterns are known, look for any links that might be within data and expand them
        //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
        parseAllLinks(patternlab);

        //dive again to recursively include partials, filling out the
        //extendedTemplate property of the patternlab.patterns elements

        return patternlab
          .processAllPatternsRecursive(paths.source.patterns)
          .then(() => {
            //take the user defined head and foot and process any data and patterns that apply

            //todo this need to be made aware of multiple ui kits
            //perhaps we can check for a convention like [uikitname]_00-head.mustache, and if found, add them to patternlab.uikits[uikitname].userFoot
            //then, if present, use those during compose()
            const headPatternPromise = processMetaPattern(
              `_00-head.${patternlab.config.patternExtension}`,
              'userHead',
              patternlab
            );
            const footPatternPromise = processMetaPattern(
              `_01-foot.${patternlab.config.patternExtension}`,
              'userFoot',
              patternlab
            );

            return Promise.all([headPatternPromise, footPatternPromise])
              .then(() => {
                //cascade any patternStates
                lineage_hunter.cascade_pattern_states(patternlab);

                //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
                return render(
                  Pattern.createEmpty({
                    extendedTemplate: patternlab.header,
                  }),
                  {
                    cacheBuster: patternlab.cacheBuster,
                  }
                )
                  .then(results => {
                    patternlab.data.patternLabHead = results;

                    // If deletePatternDir == true or graph needs to be updated
                    // rebuild all patterns
                    let patternsToBuild = null;

                    // If deletePatternDir == true or graph needs to be updated
                    // rebuild all patterns
                    patternsToBuild = null;

                    if (patternlab.incrementalBuildsEnabled) {
                      // When the graph was loaded from file, some patterns might have been moved/deleted between runs
                      // so the graph data become out of sync
                      patternlab.graph.sync().forEach(n => {
                        logger.info('[Deleted/Moved] ' + n);
                      });

                      // TODO Find created or deleted files
                      const now = new Date().getTime();
                      markModifiedPatterns(now, patternlab);
                      patternsToBuild = patternlab.graph.compileOrder();
                    } else {
                      // build all patterns, mark all to be rebuilt
                      patternsToBuild = patternlab.patterns;
                      for (const p of patternsToBuild) {
                        p.compileState = CompileState.NEEDS_REBUILD;
                      }
                    }
                    //render all patterns last, so lineageR works
                    const allPatternsPromise = patternsToBuild.map(pattern =>
                      compose(pattern, patternlab)
                    );
                    //copy non-pattern files like JavaScript
                    const allJS = patternsToBuild.map(pattern => {
                      const { name, patternPartial, subdir } = pattern;
                      const {
                        source: { patterns: sourceDir },
                        public: { patterns: publicDir },
                      } = patternlab.config.paths;
                      const src = path.join(sourceDir, subdir);
                      const dest = path.join(publicDir, name);
                      return copy(src, dest, {
                        overwrite: true,
                        filter: ['*.js'],
                        rename: () => {
                          return `${patternPartial}.js`;
                        },
                      }).on(copy.events.COPY_FILE_COMPLETE, () => {
                        logger.debug(
                          `Copied JavaScript files from ${src} to ${dest}`
                        );
                      });
                    });
                    return Promise.all(concat(allPatternsPromise, allJS))
                      .then(() => {
                        // Saves the pattern graph when all files have been compiled
                        PatternGraph.storeToFile(patternlab);
                        if (patternlab.config.exportToGraphViz) {
                          PatternGraph.exportToDot(
                            patternlab,
                            'dependencyGraph.dot'
                          );
                          logger.info(
                            `Exported pattern graph to ${path.join(
                              patternlab.config.paths.public.root,
                              'dependencyGraph.dot'
                            )}`
                          );
                        }

                        //export patterns if necessary
                        pattern_exporter.export_patterns(patternlab);
                      })
                      .catch(reason => {
                        console.log(reason);
                        logger.error('Error rendering patterns');
                      });
                  })
                  .catch(reason => {
                    console.log(reason);
                    logger.error('Error rendering pattern lab header');
                  });
              })
              .catch(reason => {
                console.log(reason);
                logger.error('Error processing meta patterns');
              });
          })
          .catch(reason => {
            console.log(reason);
            logger.error('Error processing patterns recursively');
          });
      })
      .catch(reason => {
        console.log(reason);
        logger.error('Error in buildPatterns()');
      });
  });
};
<commit_msg>feat(uikits): copy pattern-specific javascript<commit_after>'use strict';

const { concat, map } = require('lodash');
const copy = require('recursive-copy');
const path = require('path');

const cleanBuildDirectory = require('./cleanBuildDirectory');
const compose = require('./compose');
const events = require('./events');
const loadPatternGraph = require('./loadPatternGraph');
const logger = require('./log');
const PatternGraph = require('./pattern_graph').PatternGraph;
const CompileState = require('./object_factory').CompileState;
const processMetaPattern = require('./processMetaPattern');
const pe = require('./pattern_exporter');
const lh = require('./lineage_hunter');
const markModifiedPatterns = require('./markModifiedPatterns');
const parseAllLinks = require('./parseAllLinks');
const render = require('./render');
const Pattern = require('./object_factory').Pattern;

let fs = require('fs-extra'); // eslint-disable-line
let ui_builder = require('./ui_builder'); // eslint-disable-line
let copier = require('./copier'); // eslint-disable-line
let pattern_exporter = new pe(); // eslint-disable-line
let serve = require('./serve'); // eslint-disable-line

const lineage_hunter = new lh();

module.exports = (deletePatternDir, patternlab, additionalData) => {
  patternlab.events.emit(events.PATTERNLAB_BUILD_PATTERN_START, patternlab);

  const paths = patternlab.config.paths;

  //
  // CHECK INCREMENTAL BUILD GRAPH
  //
  const graph = (patternlab.graph = loadPatternGraph(
    patternlab,
    deletePatternDir
  ));
  const graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
  if (graphNeedsUpgrade) {
    logger.info(
      'Due to an upgrade, a complete rebuild is required and the public/patterns directory was deleted. ' +
        'Incremental build is available again on the next successful run.'
    );

    // Ensure that the freshly built graph has the latest version again.
    patternlab.graph.upgradeVersion();
  }

  // Flags
  patternlab.incrementalBuildsEnabled = !(
    deletePatternDir || graphNeedsUpgrade
  );

  //
  // CLEAN BUILD DIRECTORY, maybe
  //
  return cleanBuildDirectory(
    patternlab.incrementalBuildsEnabled,
    patternlab
  ).then(() => {
    patternlab.buildGlobalData(additionalData);

    return patternlab
      .processAllPatternsIterative(paths.source.patterns)
      .then(() => {
        patternlab.events.emit(
          events.PATTERNLAB_PATTERN_ITERATION_END,
          patternlab
        );

        //now that all the main patterns are known, look for any links that might be within data and expand them
        //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
        parseAllLinks(patternlab);

        //dive again to recursively include partials, filling out the
        //extendedTemplate property of the patternlab.patterns elements

        return patternlab
          .processAllPatternsRecursive(paths.source.patterns)
          .then(() => {
            //take the user defined head and foot and process any data and patterns that apply

            //todo this need to be made aware of multiple ui kits
            //perhaps we can check for a convention like [uikitname]_00-head.mustache, and if found, add them to patternlab.uikits[uikitname].userFoot
            //then, if present, use those during compose()
            const headPatternPromise = processMetaPattern(
              `_00-head.${patternlab.config.patternExtension}`,
              'userHead',
              patternlab
            );
            const footPatternPromise = processMetaPattern(
              `_01-foot.${patternlab.config.patternExtension}`,
              'userFoot',
              patternlab
            );

            return Promise.all([headPatternPromise, footPatternPromise])
              .then(() => {
                //cascade any patternStates
                lineage_hunter.cascade_pattern_states(patternlab);

                //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
                return render(
                  Pattern.createEmpty({
                    extendedTemplate: patternlab.header,
                  }),
                  {
                    cacheBuster: patternlab.cacheBuster,
                  }
                )
                  .then(results => {
                    patternlab.data.patternLabHead = results;

                    // If deletePatternDir == true or graph needs to be updated
                    // rebuild all patterns
                    let patternsToBuild = null;

                    // If deletePatternDir == true or graph needs to be updated
                    // rebuild all patterns
                    patternsToBuild = null;

                    if (patternlab.incrementalBuildsEnabled) {
                      // When the graph was loaded from file, some patterns might have been moved/deleted between runs
                      // so the graph data become out of sync
                      patternlab.graph.sync().forEach(n => {
                        logger.info('[Deleted/Moved] ' + n);
                      });

                      // TODO Find created or deleted files
                      const now = new Date().getTime();
                      markModifiedPatterns(now, patternlab);
                      patternsToBuild = patternlab.graph.compileOrder();
                    } else {
                      // build all patterns, mark all to be rebuilt
                      patternsToBuild = patternlab.patterns;
                      for (const p of patternsToBuild) {
                        p.compileState = CompileState.NEEDS_REBUILD;
                      }
                    }
                    //render all patterns last, so lineageR works
                    const allPatternsPromise = patternsToBuild.map(pattern =>
                      compose(pattern, patternlab)
                    );
                    //copy non-pattern files like JavaScript
                    const allJS = patternsToBuild.map(pattern => {
                      const { name, patternPartial, subdir } = pattern;
                      const {
                        source: { patterns: sourceDir },
                        public: { patterns: publicDir },
                      } = patternlab.config.paths;
                      const src = path.join(sourceDir, subdir);
                      const dest = path.join(publicDir, name);
                      return map(patternlab.uikits, uikit => {
                        return copy(
                          src,
                          path.resolve(process.cwd(), uikit.outputDir, dest),
                          {
                            overwrite: true,
                            filter: ['*.js'],
                            rename: () => {
                              return `${patternPartial}.js`;
                            },
                          }
                        ).on(copy.events.COPY_FILE_COMPLETE, () => {
                          logger.debug(
                            `Copied JavaScript files from ${src} to ${dest}`
                          );
                        });
                      });
                    });
                    return Promise.all(concat(allPatternsPromise, allJS))
                      .then(() => {
                        // Saves the pattern graph when all files have been compiled
                        PatternGraph.storeToFile(patternlab);
                        if (patternlab.config.exportToGraphViz) {
                          PatternGraph.exportToDot(
                            patternlab,
                            'dependencyGraph.dot'
                          );
                          logger.info(
                            `Exported pattern graph to ${path.join(
                              patternlab.config.paths.public.root,
                              'dependencyGraph.dot'
                            )}`
                          );
                        }

                        //export patterns if necessary
                        pattern_exporter.export_patterns(patternlab);
                      })
                      .catch(reason => {
                        console.log(reason);
                        logger.error('Error rendering patterns');
                      });
                  })
                  .catch(reason => {
                    console.log(reason);
                    logger.error('Error rendering pattern lab header');
                  });
              })
              .catch(reason => {
                console.log(reason);
                logger.error('Error processing meta patterns');
              });
          })
          .catch(reason => {
            console.log(reason);
            logger.error('Error processing patterns recursively');
          });
      })
      .catch(reason => {
        console.log(reason);
        logger.error('Error in buildPatterns()');
      });
  });
};
<|endoftext|>


<commit_before>if(!window.calendar_languages) {
	window.calendar_languages = {};
}

window.calendar_languages['zh-CN'] = {
	error_noview:     'Calendar: 没有发现视图 {0} ',
	error_dateformat: 'Calendar: 日期格式不正确： {0}. 应当为 "now" 或者 "yyyy-mm-dd"',
	error_loadurl:    'Calendar: 没有设置事件的 URL',
	error_where:      'Calendar: Wrong navigation direction {0}. Can be only "next" or "prev" or "today"',
	error_timedevide: 'Calendar: Time split parameter should divide 60 without decimals. Something like 10, 15, 30',

	no_events_in_day: '今天没有事件。',

	title_year:       '{0}',
	title_month:      '{1} 年 {0}',
	title_week:       '{1} 年 第 {0} 周 ',
	title_day:        '{3} 年 {2} {1} 日， {0} ',

	week:        '第{0}周',
	all_day:     '整天',
	time:        '时间',
	events:      '发展',
	before_time: '时间前结束带',
	after_time:  '临时磁带结束后，',

	m0:  '1 月',
	m1:  '2 月',
	m2:  '3 月',
	m3:  '4 月',
	m4:  '5 月',
	m5:  '6 月',
	m6:  '7 月',
	m7:  '8 月',
	m8:  '9 月',
	m9:  '10 月',
	m10: '11 月',
	m11: '12 月',

	ms0:  '1 月',
	ms1:  '2 月',
	ms2:  '3 月',
	ms3:  '4 月',
	ms4:  '5 月',
	ms5:  '6 月',
	ms6:  '7 月',
	ms7:  '8 月',
	ms8:  '9 月',
	ms9:  '10 月',
	ms10: '11 月',
	ms11: '12 月',

	d0:        '周日',
	d1:        '周一',
	d2:        '周二',
	d3:        '周三',
	d4:        '周四',
	d5:        '周五',
	d6:        '周六',

	first_day: 2,

	holidays:  {
		'01-01': '元旦',
		'08-03': '妇女节',
		'01-05': '国际劳动节',
		'04-05': '青年节',
		'01-06': '儿童节',
		'01-10': '国庆节'
	}
};
<commit_msg>完善中文语言扩展<commit_after>if(!window.calendar_languages) {
	window.calendar_languages = {};
}

window.calendar_languages['zh-CN'] = {
	error_noview:     'Calendar: 没有发现视图 {0} ',
	error_dateformat: 'Calendar: 日期格式不正确： {0}. 应当为 "now" 或者 "yyyy-mm-dd"',
	error_loadurl:    'Calendar: 没有设置事件的 URL',
	error_where:      'Calendar: 导航指示错误 {0}. 只能是 "next" 或 "prev" 或 "today"',
	error_timedevide: 'Calendar: 时间分隔参数只能是被60整除的整数. 例如 10、15、30',

	no_events_in_day: '今天没有事件。',

	title_year:       '{0}',
	title_month:      '{1} 年 {0}',
	title_week:       '{1} 年 第 {0} 周 ',
	title_day:        '{3} 年 {2} {1} 日， {0} ',

	week:        '第{0}周',
	all_day:     '全天',
	time:        '时间',
	events:      '事件',
	before_time: '结束早于时间轴',
	after_time:  '开始晚于时间轴',

	m0:  '1 月',
	m1:  '2 月',
	m2:  '3 月',
	m3:  '4 月',
	m4:  '5 月',
	m5:  '6 月',
	m6:  '7 月',
	m7:  '8 月',
	m8:  '9 月',
	m9:  '10 月',
	m10: '11 月',
	m11: '12 月',

	ms0:  '1 月',
	ms1:  '2 月',
	ms2:  '3 月',
	ms3:  '4 月',
	ms4:  '5 月',
	ms5:  '6 月',
	ms6:  '7 月',
	ms7:  '8 月',
	ms8:  '9 月',
	ms9:  '10 月',
	ms10: '11 月',
	ms11: '12 月',

	d0:        '周日',
	d1:        '周一',
	d2:        '周二',
	d3:        '周三',
	d4:        '周四',
	d5:        '周五',
	d6:        '周六',

	first_day: 2,

	holidays:  {
		'01-01': '元旦',
		'08-03': '妇女节',
		'01-05': '国际劳动节',
		'04-05': '青年节',
		'01-06': '儿童节',
		'01-10': '国庆节'
	}
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
const inquirer = require('inquirer');
const program = require('commander');
const childProcess = require('child_process');
const chalk = require('chalk');
const log = require('npmlog');
const path = require('path');

log.heading = 'storybook';
const prefix = 'test';
log.addLevel('aborted', 3001, { fg: 'red', bold: true });

const spawn = command => {
  const out = childProcess.spawnSync(`${command}`, {
    shell: true,
    stdio: 'inherit',
  });

  if (out.status !== 0) {
    process.exit(out.status);
  }

  return out;
};

const main = program.version('3.0.0').option('--all', `Test everything ${chalk.gray('(all)')}`);

const createProject = ({ defaultValue, option, name, projectLocation, isJest }) => ({
  value: false,
  defaultValue: defaultValue || false,
  option: option || undefined,
  name: name || 'unnamed task',
  projectLocation,
  isJest,
});
const createOption = ({ defaultValue, option, name, extraParam }) => ({
  value: false,
  defaultValue: defaultValue || false,
  option: option || undefined,
  name: name || 'unnamed task',
  extraParam,
});

const tasks = {
  core: createProject({
    name: `Core & React & Vue & Polymer & Angular & Svelte ${chalk.gray('(core)')}`,
    defaultValue: true,
    option: '--core',
    projectLocation: path.join(__dirname, '..'),
    isJest: true,
  }),
  'react-native-vanilla': createProject({
    name: `React-Native example ${chalk.gray('(react-native-vanilla)')}`,
    defaultValue: true,
    option: '--reactnative',
    projectLocation: path.join(__dirname, '..', 'examples/react-native-vanilla'),
    isJest: true,
  }),
  image: createProject({
    name: `Image snapshots for Official storybook ${chalk.gray('(image)')}`,
    defaultValue: false,
    option: '--image',
    projectLocation: path.join(__dirname, '..', 'examples/official-storybook/image-snapshots'),
    isJest: true,
  }),
  // 'crna-kitchen-sink': createProject({
  //   name: `React-Native-App example ${chalk.gray('(crna-kitchen-sink)')}  ${chalk.red(
  //     '[not implemented yet]'
  //   )}`,
  //   defaultValue: false,
  //   option: '--reactnativeapp',
  //   projectLocation: './examples/crna-kitchen-sink',
  //   isJest: true,
  // }),
  cli: createProject({
    name: `Command Line Interface ${chalk.gray('(cli)')}`,
    defaultValue: false,
    option: '--cli',
    script: './scripts/run-e2e.sh',
  }),
  watchmode: createOption({
    name: `Run in watch-mode ${chalk.gray('(watchmode)')}`,
    defaultValue: false,
    option: '--watch',
    extraParam: '--watch',
  }),
  coverage: createOption({
    name: `Output coverage reports ${chalk.gray('(coverage)')}`,
    defaultValue: false,
    option: '--coverage',
    extraParam: '--coverage',
  }),
  runInBand: createOption({
    name: `Run all tests serially in the current process ${chalk.gray('(runInBand)')}`,
    defaultValue: false,
    option: '--runInBand',
    extraParam: '--runInBand',
  }),
  update: createOption({
    name: `Update all snapshots ${chalk.gray('(update)')}`,
    defaultValue: false,
    option: '--update',
    extraParam: '-u --updateSnapshot',
  }),
  teamcity: createOption({
    name: `Use TeamCity reporter`,
    defaultValue: false,
    option: '--teamcity',
    extraParam: '--testResultsProcessor=jest-teamcity-reporter',
  }),
};

const getProjects = list => list.filter(key => key.projectLocation);

const getScripts = list => list.filter(key => key.script);

const getExtraParams = list => list.filter(key => key.extraParam).map(key => key.extraParam);

Object.keys(tasks)
  .reduce((acc, key) => acc.option(tasks[key].option, tasks[key].name), main)
  .parse(process.argv);

Object.keys(tasks).forEach(key => {
  tasks[key].value =
    program[tasks[key].option.replace('--', '')] || (program.all && tasks[key].projectLocation);
});

let selection;

if (
  !Object.keys(tasks)
    .map(key => tasks[key].value)
    .filter(Boolean).length
) {
  selection = inquirer
    .prompt([
      {
        type: 'checkbox',
        message: 'Select which tests to run',
        name: 'todo',
        pageSize: 18,
        choices: Object.values(tasks)
          .filter(key => !key.extraParam)
          .map(key => ({
            name: key.name,
            checked: key.defaultValue,
          }))
          .concat(new inquirer.Separator())
          .concat(
            Object.keys(tasks)
              .map(key => tasks[key])
              .filter(key => key.extraParam)
              .map(key => ({
                name: key.name,
                checked: key.defaultValue,
              }))
          ),
      },
    ])
    .then(({ todo }) =>
      todo.map(name => tasks[Object.keys(tasks).find(i => tasks[i].name === name)])
    );
} else {
  selection = Promise.resolve(
    Object.keys(tasks)
      .map(key => tasks[key])
      .filter(item => item.value === true)
  );
}

selection
  .then(list => {
    if (list.length === 0) {
      log.warn(prefix, 'Nothing to test');
    } else {
      const projects = getProjects(list);
      const jestProjects = projects.filter(key => key.isJest).map(key => key.projectLocation);
      const nonJestProjects = projects.filter(key => !key.isJest);
      const extraParams = getExtraParams(list).join(' ');
      if (jestProjects.length > 0) {
        spawn(`jest --projects ${jestProjects.join(' ')} ${extraParams}`);
      }
      nonJestProjects.forEach(key =>
        spawn(`npm --prefix ${key.projectLocation} test -- ${extraParams}`)
      );
      const scripts = getScripts(list);
      console.log(list);
      console.log(scripts);
      scripts.forEach(key => spawn(`${key.script} -- ${extraParams}`));

      process.stdout.write('\x07');
    }
  })
  .catch(e => {
    log.aborted(prefix, chalk.red(e.message));
    log.silly(prefix, e);
    process.exit(1);
  });
<commit_msg>FIX scripts/test.js<commit_after>#!/usr/bin/env node
const inquirer = require('inquirer');
const program = require('commander');
const childProcess = require('child_process');
const chalk = require('chalk');
const log = require('npmlog');
const path = require('path');

log.heading = 'storybook';
const prefix = 'test';
log.addLevel('aborted', 3001, { fg: 'red', bold: true });

const spawn = command => {
  const out = childProcess.spawnSync(`${command}`, {
    shell: true,
    stdio: 'inherit',
  });

  if (out.status !== 0) {
    process.exit(out.status);
  }

  return out;
};

const main = program.version('3.0.0').option('--all', `Test everything ${chalk.gray('(all)')}`);

const createProject = ({ defaultValue, option, name, projectLocation, isJest, script }) => ({
  value: false,
  defaultValue: defaultValue || false,
  option: option || undefined,
  name: name || 'unnamed task',
  script,
  projectLocation,
  isJest,
});
const createOption = ({ defaultValue, option, name, extraParam }) => ({
  value: false,
  defaultValue: defaultValue || false,
  option: option || undefined,
  name: name || 'unnamed task',
  extraParam,
});

const tasks = {
  core: createProject({
    name: `Core & React & Vue & Polymer & Angular & Svelte ${chalk.gray('(core)')}`,
    defaultValue: true,
    option: '--core',
    projectLocation: path.join(__dirname, '..'),
    isJest: true,
  }),
  'react-native-vanilla': createProject({
    name: `React-Native example ${chalk.gray('(react-native-vanilla)')}`,
    defaultValue: true,
    option: '--reactnative',
    projectLocation: path.join(__dirname, '..', 'examples/react-native-vanilla'),
    isJest: true,
  }),
  image: createProject({
    name: `Image snapshots for Official storybook ${chalk.gray('(image)')}`,
    defaultValue: false,
    option: '--image',
    projectLocation: path.join(__dirname, '..', 'examples/official-storybook/image-snapshots'),
    isJest: true,
  }),
  // 'crna-kitchen-sink': createProject({
  //   name: `React-Native-App example ${chalk.gray('(crna-kitchen-sink)')}  ${chalk.red(
  //     '[not implemented yet]'
  //   )}`,
  //   defaultValue: false,
  //   option: '--reactnativeapp',
  //   projectLocation: './examples/crna-kitchen-sink',
  //   isJest: true,
  // }),
  cli: createProject({
    name: `Command Line Interface ${chalk.gray('(cli)')}`,
    defaultValue: false,
    option: '--cli',
    script: './scripts/run-e2e.sh',
  }),
  watchmode: createOption({
    name: `Run in watch-mode ${chalk.gray('(watchmode)')}`,
    defaultValue: false,
    option: '--watch',
    extraParam: '--watch',
  }),
  coverage: createOption({
    name: `Output coverage reports ${chalk.gray('(coverage)')}`,
    defaultValue: false,
    option: '--coverage',
    extraParam: '--coverage',
  }),
  runInBand: createOption({
    name: `Run all tests serially in the current process ${chalk.gray('(runInBand)')}`,
    defaultValue: false,
    option: '--runInBand',
    extraParam: '--runInBand',
  }),
  update: createOption({
    name: `Update all snapshots ${chalk.gray('(update)')}`,
    defaultValue: false,
    option: '--update',
    extraParam: '-u --updateSnapshot',
  }),
  teamcity: createOption({
    name: `Use TeamCity reporter`,
    defaultValue: false,
    option: '--teamcity',
    extraParam: '--testResultsProcessor=jest-teamcity-reporter',
  }),
};

const getProjects = list => list.filter(key => key.projectLocation);

const getScripts = list => list.filter(key => key.script);

const getExtraParams = list => list.filter(key => key.extraParam).map(key => key.extraParam);

Object.keys(tasks)
  .reduce((acc, key) => acc.option(tasks[key].option, tasks[key].name), main)
  .parse(process.argv);

Object.keys(tasks).forEach(key => {
  tasks[key].value =
    program[tasks[key].option.replace('--', '')] || (program.all && tasks[key].projectLocation);
});

let selection;

if (
  !Object.keys(tasks)
    .map(key => tasks[key].value)
    .filter(Boolean).length
) {
  selection = inquirer
    .prompt([
      {
        type: 'checkbox',
        message: 'Select which tests to run',
        name: 'todo',
        pageSize: 18,
        choices: Object.values(tasks)
          .filter(key => !key.extraParam)
          .map(key => ({
            name: key.name,
            checked: key.defaultValue,
          }))
          .concat(new inquirer.Separator())
          .concat(
            Object.keys(tasks)
              .map(key => tasks[key])
              .filter(key => key.extraParam)
              .map(key => ({
                name: key.name,
                checked: key.defaultValue,
              }))
          ),
      },
    ])
    .then(({ todo }) =>
      todo.map(name => tasks[Object.keys(tasks).find(i => tasks[i].name === name)])
    );
} else {
  selection = Promise.resolve(
    Object.keys(tasks)
      .map(key => tasks[key])
      .filter(item => item.value === true)
  );
}

selection
  .then(list => {
    if (list.length === 0) {
      log.warn(prefix, 'Nothing to test');
    } else {
      const projects = getProjects(list);
      const jestProjects = projects.filter(key => key.isJest).map(key => key.projectLocation);
      const nonJestProjects = projects.filter(key => !key.isJest);
      const extraParams = getExtraParams(list).join(' ');
      if (jestProjects.length > 0) {
        spawn(`jest --projects ${jestProjects.join(' ')} ${extraParams}`);
      }
      nonJestProjects.forEach(key =>
        spawn(`npm --prefix ${key.projectLocation} test -- ${extraParams}`)
      );
      const scripts = getScripts(list);
      scripts.forEach(key => spawn(`${key.script} -- ${extraParams}`));

      process.stdout.write('\x07');
    }
  })
  .catch(e => {
    log.aborted(prefix, chalk.red(e.message));
    log.silly(prefix, e);
    process.exit(1);
  });
<|endoftext|>


<commit_before>/** Script ACLs do not delete
 read=nobody
write=nobody
execute=authenticated
  **/

 var clientModule = require("./client.js");
var config = require("./oauth2/config.js");
var util = require("./util.js");

/**
 * This class wraps the data of a carvoyant user and exposes methods for all
 * the operations that relate to a given user
 * @class User
 * @constructor User
 * @param {Object} dto : intialization parameters
 *	{String} dto.username : the name of the carvoyant user (as specified during the OAuth authorization process)
 */
function User(dto) {

  this.username = dto.username;
  this.client = new clientModule.Client(dto);
}

/*
 * List all the carvoyant accounts of the current user
 * This method can throw exceptions
 * @method listAccounts
 * @return {Object} : [ // an array
 * 			{"id": value, "firstName": value, "lastName": value, "username": value, "dateCreated": value, "email": value, "zipcode": value,
 *			"phone": value,	"timeZone": value,	"preferredContact": value}, ...,
 *     ]
 */
User.prototype.listAccounts = function() {

  var query = {

     url : config.apiUrl + "/account",
     method : "GET"
  };

  var result = this.client.callApi(query);
  for (var i = 0; i < result.account.length; i++) {
  	result.account[i].dateCreated = util.toReadableDateTime(result.account[i].dateCreated);
  }

  return {
    "accounts": result.account,
    "totalRecords": result.totalRecords
  };
};

/**
 * Retrieve the list of carvoyant accounts for the current user and store their ids in the global storage,
 * This method is mainly used internally when receiving notifications in order to identify the targeted user
 */
User.prototype.persistAccountIds = function() {

  var result = this.listAccounts();
  var key = config.app + "_accountId_";
  var accountIds = [];
  for (var i = 0; i < result.accounts.length; i++) {

    key += result.accounts[i].id;
    if (!storage.global[key] || storage.global[key].length == 0) {

      accountIds.push(result.accounts[i].id);
      storage.global[key] = this.username;
    }
  }
};

/**
 * Get detailed data about a given user account
 * @method getAccount
 * @param {String} accountId : the identifier of a carvoyance user account
 * @return {Object}
 * {
 *	"id": value, "firstName": value, "lastName": value, "username": value, "dateCreated": value,
 *	"email": value, "zipcode": value, phone": value, "timeZone": value, "preferredContact": "EMAIL"
 * }
 */
User.prototype.getAccount = function(accountId) {

  if (!accountId) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.getAccount : accountId cannot be null or empty"
    };
  }

  var query = {

     url : config.apiUrl + "/account/" +  accountId,
     method : "GET"
  };

  var result = this.client.callApi(query);
  result.account.dateCreated = util.toReadableDateTime(result.account.dateCreated);
  return result.account;
};

/**
 * List all the known vehicle of the current user
 * This method can throw exceptions
 * @method listVehicles
 * @return {Object} [
 *		{"name": value, "label": value, "vehicleId": value, "vin": value, "mileage": value,
 *		"lastWaypoint": { "timestamp": value, "latitude": value, "longitude": value} // this is optional,
 *		"lastRunningTimestamp": value, "autoAssignDevice": true/false, "mil": true/false},
 *		{...}, ...
 *   ]
 */
User.prototype.listVehicles = function() {

  var query = {

    url : config.apiUrl + "/vehicle",
    method : "GET"
  };

  var result = this.client.callApi(query);
  var vehicles = result.vehicle;
  for (var i = 0; i < vehicles.length; i++) {

    if (vehicles[i].lastRunningTimestamp) {
      vehicles[i].lastRunningTimestamp = util.toReadableDateTime(vehicles[i].lastRunningTimestamp);
    }

    if (vehicles[i].lastWaypoint) {
      vehicles[i].lastWaypoint.timestamp = util.toReadableDateTime(vehicles[i].lastWaypoint.timestamp);
    }
  }
  return vehicles;
};

/**
 * @method getVehicle
 * @param {String} the identifer of a vehicle owned by the current user
 * @return {Object} instance of the Vehicle class wrapping the requested vehicle
 */
User.prototype.getVehicle = function(vehicleId) {

  var vehicleModule = require("carvoyant/vehicle.js");
  var vehicle = new vehicleModule.Vehicle({username:this.username, vehicleId:vehicleId});
  return vehicle;
};

/**
 * @method addVehicle
 * @param {Object} params
 * 	{String} params.deviceId: value,
 *	{String} params.vin: valueOn17Chars,
 *	{String} params.label: value, // mandatory
 *	{Numeric} param.mileage: value
 * @return {Object} same as params
 */
User.prototype.addVehicle = function(params) {

  if (!params || !params.label) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.addVehicle : label cannot be null or empty"
    };
  }

  return this._saveVehicle(params);
};

/**
 * @method updateVehicle
 * @param {Object} params
 * 	{String} params.deviceId: value, // mandatory, used to identify the vehicle
 *	{String} params.vin: valueOn17Chars,
 *	{String} params.label: value, // mandatory
 *	{Numeric} param.mileage: value
 * @return {Object} same as params
 */
User.prototype.updateVehicle = function(params) {

  if (!params || !params.label || !params.vehicleId) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.addVehicle : vehicleId and label cannot be null or empty"
    };
  }

  return this._saveVehicle(params, true);
};

/**
 * @method deleteVehicle
 * @param {String} vehicleId : the identifier of the vehicle to delete
 * @return {String} the vehicleId
 */
User.prototype.deleteVehicle = function(vehicleId) {

  var request = {

    url : config.apiUrl + "/vehicle/" + vehicleId,
    method : "DELETE",
    headers : {
      "Content-Type": "application/json"
    }
  };

  var result = this.client.callApi(request);
  if (result.result == "OK") {
  	return vehicleId;
  }else {

    throw {
      "errorCode": "Error_Occured",
      "errorDetail": result
    }
  };
};

User.prototype._saveVehicle = function(params, update) {

  var request = {

    url : config.apiUrl + "/vehicle" + (update ? "/" + params.vehicleId : ""),
    method : "POST",
    headers : {
      "Content-Type": "application/json"
    },
    bodyString: JSON.stringify(params)
  };

  var result = this.client.callApi(request);
  return result.vehicle;
};

/**
 * Factory method that returns an instance of User based on the provided
 * carvoyant accountId
 * @static
 * @method getUserFromAccountId
 * @param {String} accountId: a carvoyant accountId
 * @return
 */
function getUserFromAccountId(accountId) {

  if (accountId) {

    var key = config.app + "_accountId_" +  accountId;
    return new User({username: storage.global[key]});
  }
};			<commit_msg>Update user.js<commit_after>/** Script ACLs do not delete
 read=nobody
write=nobody
execute=authenticated
  **/

 var clientModule = require("./client.js");
var config = require("./oauth2/config.js");
var util = require("./util.js");

/**
 * This class wraps the data of a carvoyant user and exposes methods for all
 * the operations that relate to a given user
 * @class User
 * @constructor User
 * @param {Object} dto : intialization parameters
 *	{String} dto.username : the name of the carvoyant user (as specified during the OAuth authorization process)
 */
function User(dto) {

  this.username = dto.username;
  this.client = new clientModule.Client(dto);
}

/*
 * List all the carvoyant accounts of the current user
 * This method can throw exceptions
 * @method listAccounts
 * @return {Object} : [ // an array
 * 			{"id": value, "firstName": value, "lastName": value, "username": value, "dateCreated": value, "email": value, "zipcode": value,
 *			"phone": value,	"timeZone": value,	"preferredContact": value}, ...,
 *     ]
 */
User.prototype.listAccounts = function() {

  var query = {

     url : config.apiUrl + "/account",
     method : "GET"
  };

  var result = this.client.callApi(query);
  for (var i = 0; i < result.account.length; i++) {
  	result.account[i].dateCreated = util.toReadableDateTime(result.account[i].dateCreated);
  }

  return {
    "accounts": result.account,
    "totalRecords": result.totalRecords
  };
};

/**
 * Retrieve the list of carvoyant accounts for the current user and store their ids in the global storage,
 * This method is mainly used internally when receiving notifications in order to identify the targeted user
 */
User.prototype.persistAccountIds = function() {

  var result = this.listAccounts();
  var key = config.app + "_accountId_";
  var accountIds = [];
  for (var i = 0; i < result.accounts.length; i++) {

    key += result.accounts[i].id;
    if (!storage.global[key] || storage.global[key].length == 0) {

      accountIds.push(result.accounts[i].id);
      storage.global[key] = this.username;
    }
  }
};

/**
 * Get detailed data about a given user account
 * @method getAccount
 * @param {String} accountId : the identifier of a carvoyance user account
 * @return {Object}
 * {
 *	"id": value, "firstName": value, "lastName": value, "username": value, "dateCreated": value,
 *	"email": value, "zipcode": value, phone": value, "timeZone": value, "preferredContact": "EMAIL"
 * }
 */
User.prototype.getAccount = function(accountId) {

  if (!accountId) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.getAccount : accountId cannot be null or empty"
    };
  }

  var query = {

     url : config.apiUrl + "/account/" +  accountId,
     method : "GET"
  };

  var result = this.client.callApi(query);
  result.account.dateCreated = util.toReadableDateTime(result.account.dateCreated);
  return result.account;
};

/**
 * List all the known vehicle of the current user
 * This method can throw exceptions
 * @method listVehicles
 * @return {Object} [
 *		{"name": value, "label": value, "vehicleId": value, "vin": value, "mileage": value,
 *		"lastWaypoint": { "timestamp": value, "latitude": value, "longitude": value} // this is optional,
 *		"lastRunningTimestamp": value, "autoAssignDevice": true/false, "mil": true/false},
 *		{...}, ...
 *   ]
 */
User.prototype.listVehicles = function() {

  var query = {

    url : config.apiUrl + "/vehicle",
    method : "GET"
  };

  var result = this.client.callApi(query);
  var vehicles = result.vehicle;
  for (var i = 0; i < vehicles.length; i++) {

    if (vehicles[i].lastRunningTimestamp) {
      vehicles[i].lastRunningTimestamp = util.toReadableDateTime(vehicles[i].lastRunningTimestamp);
    }

    if (vehicles[i].lastWaypoint) {
      vehicles[i].lastWaypoint.timestamp = util.toReadableDateTime(vehicles[i].lastWaypoint.timestamp);
    }
  }
  return vehicles;
};

/**
 * @method getVehicle
 * @param {String} the identifer of a vehicle owned by the current user
 * @return {Object} instance of the Vehicle class wrapping the requested vehicle
 */
User.prototype.getVehicle = function(vehicleId) {

  var vehicleModule = require("./vehicle.js");
  var vehicle = new vehicleModule.Vehicle({username:this.username, vehicleId:vehicleId});
  return vehicle;
};

/**
 * @method addVehicle
 * @param {Object} params
 * 	{String} params.deviceId: value,
 *	{String} params.vin: valueOn17Chars,
 *	{String} params.label: value, // mandatory
 *	{Numeric} param.mileage: value
 * @return {Object} same as params
 */
User.prototype.addVehicle = function(params) {

  if (!params || !params.label) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.addVehicle : label cannot be null or empty"
    };
  }

  return this._saveVehicle(params);
};

/**
 * @method updateVehicle
 * @param {Object} params
 * 	{String} params.deviceId: value, // mandatory, used to identify the vehicle
 *	{String} params.vin: valueOn17Chars,
 *	{String} params.label: value, // mandatory
 *	{Numeric} param.mileage: value
 * @return {Object} same as params
 */
User.prototype.updateVehicle = function(params) {

  if (!params || !params.label || !params.vehicleId) {

    throw {
      "errorCode": "Invalid_Parameter",
      "errorDetail": "User.addVehicle : vehicleId and label cannot be null or empty"
    };
  }

  return this._saveVehicle(params, true);
};

/**
 * @method deleteVehicle
 * @param {String} vehicleId : the identifier of the vehicle to delete
 * @return {String} the vehicleId
 */
User.prototype.deleteVehicle = function(vehicleId) {

  var request = {

    url : config.apiUrl + "/vehicle/" + vehicleId,
    method : "DELETE",
    headers : {
      "Content-Type": "application/json"
    }
  };

  var result = this.client.callApi(request);
  if (result.result == "OK") {
  	return vehicleId;
  }else {

    throw {
      "errorCode": "Error_Occured",
      "errorDetail": result
    }
  };
};

User.prototype._saveVehicle = function(params, update) {

  var request = {

    url : config.apiUrl + "/vehicle" + (update ? "/" + params.vehicleId : ""),
    method : "POST",
    headers : {
      "Content-Type": "application/json"
    },
    bodyString: JSON.stringify(params)
  };

  var result = this.client.callApi(request);
  return result.vehicle;
};

/**
 * Factory method that returns an instance of User based on the provided
 * carvoyant accountId
 * @static
 * @method getUserFromAccountId
 * @param {String} accountId: a carvoyant accountId
 * @return
 */
function getUserFromAccountId(accountId) {

  if (accountId) {

    var key = config.app + "_accountId_" +  accountId;
    return new User({username: storage.global[key]});
  }
};
<|endoftext|>


<commit_before>vde.App.controller('GroupsCtrl', function($scope, $rootScope, $timeout, logger) {
  $scope.gMdl = { // General catch-all model for scoping
    groups: vde.Vis.groups,
    pipelines: vde.Vis.pipelines
  };

  $rootScope.toggleVisual = function(v, key) {
    $rootScope.activeVisual = v;
    $rootScope.activeGroup  = v.group() || v;

    $rootScope.activePipeline = v.pipelineName ? v.pipeline() : $rootScope.activePipeline;
    $scope.gMdl.activeVisualPipeline = (v.pipeline() || {}).name;

    vde.iVis.activeMark = v;
    vde.iVis.activeItem = key || 0;
    vde.iVis.show('handle');

    logger.log('toggle_visual', {
      activeVisual: v.name,
      activeGroup: v.groupName || v.name,
      visualPipeline: v.pipelineName,
      activePipeline: ($rootScope.activePipeline||{}).name
    });
  };

  $scope.setPipeline = function() {
    var p = $scope.gMdl.activeVisualPipeline;
    if(p == '') $scope.activeVisual.pipelineName = null;
    else if(p == 'vdeNewPipeline') {
      var pipeline = new vde.Vis.Pipeline();
      $scope.activeVisual.pipelineName = pipeline.name
      $rootScope.activePipeline = pipeline;
      $scope.gMdl.activeVisualPipeline = pipeline.name;
    }
    else {
      $scope.activeVisual.pipelineName = p;
      $rootScope.activePipeline = vde.Vis.pipelines[p];
    }

    vde.Vis.parse();

    logger.log('set_pipeline', {
      activeVisual: $rootScope.activeVisual.name,
      activeGroup: $rootScope.activeGroup.name,
      activeVisualPipeline: p,
      activePipeline: $rootScope.activePipeline.name
    }, true, true);
  };

  $scope.addGroup = function() {
    var g = new vde.Vis.marks.Group();
    $rootScope.activeGroup = g;
    $rootScope.activeVisual = g;

    logger.log('new_group', {
      activeVisual: g.name,
      activeGroup: g.groupName || g.name,
      visualPipeline: g.pipelineName,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.addAxis = function() {
    var axis = new vde.Vis.Axis('', $rootScope.activeGroup.name);
    $rootScope.activeVisual = axis;

    logger.log('new_axis', {
      activeVisual: axis.name,
      activeGroup: axis.groupName || axis.name,
      visualPipeline: axis.pipelineName,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.removeVisual = function(type, name) {
    var cnf = confirm("Are you sure you wish to delete this visual element?")
    if(!cnf) return;

    if(type == 'group') delete vde.Vis.groups[name];
    else delete $rootScope.activeGroup[type][name];
    vde.Vis.parse();

    $('.tooltip').remove();

    logger.log('remove_visual', {
      type: type,
      name: name,
      activeGroup: $rootScope.activeGroup.name,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.newTransform = function(type) {
    var t = new vde.Vis.transforms[type];
    t.pipelineName = $rootScope.activeVisual.pipelineName;
    $rootScope.activeVisual.pipeline().transforms.push(t);
  };

  $scope.removeTransform = function(i) {
    var cnf = confirm("Are you sure you wish to delete this transformation?")
    if(!cnf) return;

    $rootScope.activeVisual.pipeline().transforms[i].destroy();
    $rootScope.activeVisual.pipeline().transforms.splice(i, 1);
    vde.Vis.parse();

    $('.tooltip').remove();

    logger.log('remove_transform', { idx: i }, false, true);
  };

  $scope.toggleFont = function(prop, value) {
    var p = $rootScope.activeVisual.properties[prop];
    if(p.value == value) delete p.value;
    else p.value = value;

    $rootScope.activeVisual.checkExtents(prop);

    $rootScope.activeVisual.update(prop);
  };

  $scope.editVisualization = function() {
    $rootScope.editVis = !$rootScope.editVis;
    $rootScope.vis = vde.Vis.properties;

    logger.log('edit_vis', {});
  };
});<commit_msg>Bug fix with jumping selection<commit_after>vde.App.controller('GroupsCtrl', function($scope, $rootScope, $timeout, logger) {
  $scope.gMdl = { // General catch-all model for scoping
    groups: vde.Vis.groups,
    pipelines: vde.Vis.pipelines
  };

  $rootScope.toggleVisual = function(v, key) {
    $rootScope.activeVisual = v;
    $rootScope.activeGroup  = v.group() || v;

    $rootScope.activePipeline = v.pipelineName ? v.pipeline() : $rootScope.activePipeline;
    $scope.gMdl.activeVisualPipeline = (v.pipeline() || {}).name;

    if(vde.iVis.activeMark != v || key != null) {
      vde.iVis.activeMark = v;
      vde.iVis.activeItem = key || 0;
      vde.iVis.show('handle');
    }

    logger.log('toggle_visual', {
      activeVisual: v.name,
      activeGroup: v.groupName || v.name,
      visualPipeline: v.pipelineName,
      activePipeline: ($rootScope.activePipeline||{}).name
    });
  };

  $scope.setPipeline = function() {
    var p = $scope.gMdl.activeVisualPipeline;
    if(p == '') $scope.activeVisual.pipelineName = null;
    else if(p == 'vdeNewPipeline') {
      var pipeline = new vde.Vis.Pipeline();
      $scope.activeVisual.pipelineName = pipeline.name
      $rootScope.activePipeline = pipeline;
      $scope.gMdl.activeVisualPipeline = pipeline.name;
    }
    else {
      $scope.activeVisual.pipelineName = p;
      $rootScope.activePipeline = vde.Vis.pipelines[p];
    }

    vde.Vis.parse();

    logger.log('set_pipeline', {
      activeVisual: $rootScope.activeVisual.name,
      activeGroup: $rootScope.activeGroup.name,
      activeVisualPipeline: p,
      activePipeline: $rootScope.activePipeline.name
    }, true, true);
  };

  $scope.addGroup = function() {
    var g = new vde.Vis.marks.Group();
    $rootScope.activeGroup = g;
    $rootScope.activeVisual = g;

    logger.log('new_group', {
      activeVisual: g.name,
      activeGroup: g.groupName || g.name,
      visualPipeline: g.pipelineName,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.addAxis = function() {
    var axis = new vde.Vis.Axis('', $rootScope.activeGroup.name);
    $rootScope.activeVisual = axis;

    logger.log('new_axis', {
      activeVisual: axis.name,
      activeGroup: axis.groupName || axis.name,
      visualPipeline: axis.pipelineName,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.removeVisual = function(type, name) {
    var cnf = confirm("Are you sure you wish to delete this visual element?")
    if(!cnf) return;

    if(type == 'group') delete vde.Vis.groups[name];
    else delete $rootScope.activeGroup[type][name];
    vde.Vis.parse();

    $('.tooltip').remove();

    logger.log('remove_visual', {
      type: type,
      name: name,
      activeGroup: $rootScope.activeGroup.name,
      activePipeline: $rootScope.activePipeline.name
    }, true);
  };

  $scope.newTransform = function(type) {
    var t = new vde.Vis.transforms[type];
    t.pipelineName = $rootScope.activeVisual.pipelineName;
    $rootScope.activeVisual.pipeline().transforms.push(t);
  };

  $scope.removeTransform = function(i) {
    var cnf = confirm("Are you sure you wish to delete this transformation?")
    if(!cnf) return;

    $rootScope.activeVisual.pipeline().transforms[i].destroy();
    $rootScope.activeVisual.pipeline().transforms.splice(i, 1);
    vde.Vis.parse();

    $('.tooltip').remove();

    logger.log('remove_transform', { idx: i }, false, true);
  };

  $scope.toggleFont = function(prop, value) {
    var p = $rootScope.activeVisual.properties[prop];
    if(p.value == value) delete p.value;
    else p.value = value;

    $rootScope.activeVisual.checkExtents(prop);

    $rootScope.activeVisual.update(prop);
  };

  $scope.editVisualization = function() {
    $rootScope.editVis = !$rootScope.editVis;
    $rootScope.vis = vde.Vis.properties;

    logger.log('edit_vis', {});
  };
});
<|endoftext|>


<commit_before>/**
 * @author       adoankim <adoankim@alumnos.uvigo.es>
 * @copyright    2014 adoankim
 * @license      {@link https://github.com/adoankim/PhaserGoF/blob/master/LICENSE|MIT License}
 *
 * game.js
 * Game init and states configuration
 */
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameCanvas');
require(['js/states.js']);<commit_msg>Optimize RequireJS dependencies path<commit_after>/**
 * @author       adoankim <adoankim@alumnos.uvigo.es>
 * @copyright    2014 adoankim
 * @license      {@link https://github.com/adoankim/PhaserGoF/blob/master/LICENSE|MIT License}
 *
 * game.js
 * Game init and states configuration
 */
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameCanvas');
require.config({
    paths: {
        'underscore': '/vendor/js/underscore-min'
    }
});
require(['js/states.js']);
<|endoftext|>


<commit_before>import gulp from 'gulp'
import zip from 'gulp-zip'

const TASK_NAME = 'package'

function packageTask () {
  let counter = 1
  gulp.autoRegister(TASK_NAME, config => {
    console.log('Iteration: ', counter)
    console.log('=============================\n')
    console.log('config.src: ', config.src)
    console.log('=============================\n')
    console.log('config.options.filename: ', config.options.filename)
    console.log('=============================\n')
    console.log('config.dest: ', config.dest)
    console.log('=============================')
    return gulp.src(config.src)
      .pipe(zip(config.options.filename))
      .pipe(gulp.dest(config.dest))
  })
}
console.log('Running TASK_NAME:', TASK_NAME)
console.log('\n')
console.log('packageTask', packageTask)
console.log('\n')
console.log('=============================')
gulp.task(TASK_NAME, packageTask)

export default packageTask
<commit_msg>remove logs<commit_after>import gulp from 'gulp'
import zip from 'gulp-zip'

const TASK_NAME = 'package'

function packageTask () {
  let counter = 1
  gulp.autoRegister(TASK_NAME, config => {
    return gulp.src(config.src)
      .pipe(zip(config.options.filename))
      .pipe(gulp.dest(config.dest))
  })
}

gulp.task(TASK_NAME, packageTask)

export default packageTask
<|endoftext|>


<commit_before>module.exports = {
  extends: [
    'eslint-config-airbnb-base',
    'eslint-config-airbnb-base/rules/strict',
    './rules/react',
    './rules/react-a11y',
  ].map(require.resolve),
  rules: {}
};
<commit_msg>[eslint config] Remove rules/strict from 'extends'<commit_after>module.exports = {
  extends: [
    'eslint-config-airbnb-base',
    './rules/react',
    './rules/react-a11y',
  ].map(require.resolve),
  rules: {}
};
<|endoftext|>


<commit_before>var routes = function ($stateProvider, $urlRouterProvider) {
  $urlRouterProvider.otherwise(function ($injector, $location) {
    var state = $injector.get('$state')
    window.Rollbar.warning('404 Error: ' + $location.path())
    state.go('notFound')
    return $location.path()
  })

  // handle old links
  $urlRouterProvider.when('/c/:community/s/:postId', '/p/:postId')
  $urlRouterProvider.when('/community/invite/:token', '/use-invitation?token')
  $urlRouterProvider.when('/h/login', '/login')
  $urlRouterProvider.when('/h/signup', '/signup')
  $urlRouterProvider.when('/h/forgot-password', '/forgot-password')
  $urlRouterProvider.when('/h/search', '/search')

  // handle alternate name of starting route
  $urlRouterProvider.when('/', '/app')

  $stateProvider
  .state('notFound', {
    templateUrl: '/ui/app/404.tpl.html'
  })
  .state('main', /* @ngInject*/ {
    abstract: true,
    templateUrl: '/ui/shared/main.tpl.html',
    resolve: {
      currentUser: function (CurrentUser) {
        return CurrentUser.load()
      },
      onboarding: function (currentUser, Onboarding) {
        var onboardingData = (currentUser && currentUser.onboarding)
        if (!_.any(onboardingData)) return null
        return new Onboarding(currentUser)
      }
    }
  })
  .state('userSettings', {
    url: '/settings?expand',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/user/settings.tpl.html',
        controller: 'UserSettingsCtrl'
      }
    }
  })
  .state('support', {
    url: '/h/support',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/support/base.tpl.html',
        controller: function ($anchorScroll) {
          $anchorScroll()
        }
      }
    }
  })
  .state('notifications', {
    url: '/h/notifications',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/user/notifications.tpl.html',
        controller: 'NotificationsCtrl'
      }
    },
    resolve: {
      activity: function (Activity) {
        return Activity.query({limit: 50}).$promise
      }
    }
  })
  .state('search', {
    url: '/search?q&c',
    parent: 'main',
    resolve: /* @ngInject*/ {
      initialQuery: function ($stateParams) {
        return $stateParams.q
      },
      searchCommunity: function ($stateParams, Community) {
        if ($stateParams.c) {
          return Community.get({id: $stateParams.c}).$promise
        }
      }
    },
    views: {
      main: {
        templateUrl: '/ui/app/search.tpl.html',
        controller: 'SearchCtrl'
      }
    }
  })
  .state('newPost', {
    url: '/h/new-post',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/edit.tpl.html',
        controller: 'PostEditCtrl'
      }
    },
    resolve: {
      post: () => null,
      communities: () => []
    }
  })
  .state('post', {
    url: '/p/:postId?action',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/show.tpl.html',
        controller: 'PostCtrl'
      }
    },
    resolve: {
      post: /* @ngInject*/ function (Post, $stateParams) {
        return Post.get({id: $stateParams.postId}).$promise
      }
    },
    data: {
      singlePost: true
    }
  })
  .state('editPost', {
    url: '/p/:postId/edit',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/edit.tpl.html',
        controller: 'PostEditCtrl'
      }
    },
    resolve: /* @ngInject*/ {
      post: function (Post, $stateParams) {
        return Post.get({id: $stateParams.postId}).$promise
      },
      communities: post => post.communities
    }
  })

  require('./routes/community')($stateProvider)
  require('./routes/profile')($stateProvider)
  require('./routes/onboarding')($stateProvider)
  require('./routes/home')($stateProvider)
  require('./routes/project')($stateProvider)
  require('./routes/network')($stateProvider)
  require('./routes/entrance')($stateProvider)

}

module.exports = function (angularModule) {
  angularModule.config(routes)
}
<commit_msg>add a missing ngInject<commit_after>var routes = function ($stateProvider, $urlRouterProvider) {
  $urlRouterProvider.otherwise(function ($injector, $location) {
    var state = $injector.get('$state')
    window.Rollbar.warning('404 Error: ' + $location.path())
    state.go('notFound')
    return $location.path()
  })

  // handle old links
  $urlRouterProvider.when('/c/:community/s/:postId', '/p/:postId')
  $urlRouterProvider.when('/community/invite/:token', '/use-invitation?token')
  $urlRouterProvider.when('/h/login', '/login')
  $urlRouterProvider.when('/h/signup', '/signup')
  $urlRouterProvider.when('/h/forgot-password', '/forgot-password')
  $urlRouterProvider.when('/h/search', '/search')

  // handle alternate name of starting route
  $urlRouterProvider.when('/', '/app')

  $stateProvider
  .state('notFound', {
    templateUrl: '/ui/app/404.tpl.html'
  })
  .state('main', /* @ngInject*/ {
    abstract: true,
    templateUrl: '/ui/shared/main.tpl.html',
    resolve: {
      currentUser: function (CurrentUser) {
        return CurrentUser.load()
      },
      onboarding: function (currentUser, Onboarding) {
        var onboardingData = (currentUser && currentUser.onboarding)
        if (!_.any(onboardingData)) return null
        return new Onboarding(currentUser)
      }
    }
  })
  .state('userSettings', {
    url: '/settings?expand',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/user/settings.tpl.html',
        controller: 'UserSettingsCtrl'
      }
    }
  })
  .state('support', {
    url: '/h/support',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/support/base.tpl.html',
        controller: function ($anchorScroll) {
          $anchorScroll()
        }
      }
    }
  })
  .state('notifications', {
    url: '/h/notifications',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/user/notifications.tpl.html',
        controller: 'NotificationsCtrl'
      }
    },
    resolve: {
      activity: function (Activity) {
        return Activity.query({limit: 50}).$promise
      }
    }
  })
  .state('search', {
    url: '/search?q&c',
    parent: 'main',
    resolve: /* @ngInject*/ {
      initialQuery: function ($stateParams) {
        return $stateParams.q
      },
      searchCommunity: function ($stateParams, Community) {
        if ($stateParams.c) {
          return Community.get({id: $stateParams.c}).$promise
        }
      }
    },
    views: {
      main: {
        templateUrl: '/ui/app/search.tpl.html',
        controller: 'SearchCtrl'
      }
    }
  })
  .state('newPost', {
    url: '/h/new-post',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/edit.tpl.html',
        controller: 'PostEditCtrl'
      }
    },
    resolve: {
      post: () => null,
      communities: () => []
    }
  })
  .state('post', {
    url: '/p/:postId?action',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/show.tpl.html',
        controller: 'PostCtrl'
      }
    },
    resolve: {
      post: /* @ngInject*/ function (Post, $stateParams) {
        return Post.get({id: $stateParams.postId}).$promise
      }
    },
    data: {
      singlePost: true
    }
  })
  .state('editPost', {
    url: '/p/:postId/edit',
    parent: 'main',
    views: {
      main: {
        templateUrl: '/ui/post/edit.tpl.html',
        controller: 'PostEditCtrl'
      }
    },
    resolve: /* @ngInject*/ {
      post: function (Post, $stateParams) {
        return Post.get({id: $stateParams.postId}).$promise
      },
      communities: function (post) {
        return post.communities
      }
    }
  })

  require('./routes/community')($stateProvider)
  require('./routes/profile')($stateProvider)
  require('./routes/onboarding')($stateProvider)
  require('./routes/home')($stateProvider)
  require('./routes/project')($stateProvider)
  require('./routes/network')($stateProvider)
  require('./routes/entrance')($stateProvider)

}

module.exports = function (angularModule) {
  angularModule.config(routes)
}
<|endoftext|>


<commit_before>$(function() {
	// TODO: Put constants somwhere
	var CARD_PADDING = '1.0%';
	var CARDS_PER_ROW = 3;
	var ANIMATION_TIME = 500;

	var OPEN_SIZE = {
		WIDTH: '100%',
		HEIGHT: '100%'
	};
	var CLOSED_SIZE = {
		WIDTH: 33.3,
		HEIGHT: (100/2.2)
	};
	var HIDE_SIZE = {
		WIDTH: '0%',
		HEIGHT: '0%'
	};

	// Page state variables
	var cardIsOpen = false;
	var $cardTiles = $('div.cardTiles');
	var $tileCards = $cardTiles.find('div.card');
	var numCards = $tileCards.length;
	var fitTexts = {
		'profile': [],
		'thefourelements': []
	};
	var shiftKey = false;

	// On load
	(function () {
		// Populate the fitText fields
		fitTexts['profile'].push(
			$('.profile .profileText .name').fitText(1.3),
			$('.profile .profileText .bio').fitText(3),
			$('.profile .closeButton .content').fitText(0.2),
			$('.profile .twitterHandle').fitText(7),
			$('.profile .longBio').fitText(7),
			$('.profile .experienceList .description').fitText(6),
			$('.profile .experienceList .descriptionBullets').fitText(6)
		);
		fitTexts['thefourelements'].push(
			$('.thefourelements .name').fitText(1.1),
			$('.thefourelements .description').fitText(2),
			$('.thefourelements .instructions').fitText(2),
			$('.thefourelements .plays').fitText(3)
		);

		// Resizes the profile video on window resize
		$(window).on('resize orientationchange', function () {
			// TODO: Make this happen only if the profile card is open
			resizeProfileVideo();
			resizeFlash();
		});

		// If you click outside the card, it automatically closes the opened card
		$('.cardArea').click(function (event) {
			var target = event.target;
			if ($(target).hasClass('cardArea')) {
				closeCard($('.card.open'));
			}
			return false;
		});

		// Clicking on the nav buttons
		$('.paginate.left').click(navLeft);
		$('.paginate.right').click(navRight);

		// Github
		// setGithubData();
	})();

	//
	// Events
	//

	/**
	 * When clickcing on a card, open it up.
	 */
	$tileCards.click(function() {
		if (!cardIsOpen) {
			var $card = $(this);
			openCard($card);
		}
		return false;
	});

	// Check for shift key
	$(window).keydown(function (event) {
		shiftKey = event.shiftKey;
	});
	$(window).keyup(function (event) {
		shiftKey = event.shiftKey;
	});

	/**
	 * Called during steps of a card resizing
	 * @param {String} cardId The id of the card that is being resized
	 */
	function resizing (cardId) {
		fitTexts[cardId] = fitTexts[cardId] || [];
		fitTexts[cardId].forEach(function (resize) {
			resize();
		});

		// Special resizing cards
		switch (cardId) {
			case 'profile':
				resizeProfileVideo();
				break;
			case 'thefourelements':
				resizeFlash();
				break;
		}
	}

	/**
	 * Resizes the profile video and adjusts the position to cover the parent area
	 */
	function resizeProfileVideo() {
		// Resize video
		var $video = $('.profileVideo');
		var videoWidth = $video.width();
		var videoHeight = $video.height();

		var $videoArea = $video.parent();
		var videoAreaHeight = $videoArea.height();
		var videoAreaWidth = $videoArea.width();

		var videoRatio = videoWidth/videoHeight;
		var videoAreaRatio = videoAreaWidth/videoAreaHeight;

		var margin;
		// If videoArea too flat, make 100% height
		if (videoAreaRatio < videoRatio) {
			margin = (videoAreaWidth - videoWidth)/2;
			$video.css({
				'width': 'auto',
				'height': '100%',
				'margin-top': 0,
				'margin-left': margin
			});
		} else {
			margin = (videoAreaHeight - videoHeight)/2;
			$video.css({
				'width': '100%',
				'height': 'auto',
				'margin-top': margin,
				'margin-left': 0
			});
		}
	}

	/**
	 * Resizes the flash game to fit it (not cover) the parent area
	 */
	function resizeFlash () {
		var $swf = $('.thefourelements .swf');
		if ($swf.length) {
			var $parent = $swf.parent();
			var parentWidth = $parent.width();
			var parentHeight = $parent.height();

			var swfRatio = $swf.data('aspectratio');
			swfRatio = +swfRatio.split(':')[0]/+swfRatio.split(':')[1];
			var parentRatio = parentWidth/parentHeight;

			var margin = 0;
			if (swfRatio < parentRatio) {
				// Use 100% height
				var width = parentHeight * swfRatio;
				margin = (parentWidth - width)/2;
				$swf.css({
					'width': width + 'px',
					'height': '100%',
					'margin-top': 0,
					'margin-left': margin
				});
			} else {
				// Use 100% width
				var height = parentWidth/swfRatio;
				margin = (parentHeight - height)/2;
				$swf.css({
					'width': '100%',
					'height': height + 'px',
					'margin-top': margin,
					'margin-left': 0
				});
			}
		}
	}

	//
	// Actions
	//

	/**
	 * Opens a card. Expands it to fill the view
	 * @param {Card} $card The jquery-wrapped card
	 */
	function openCard ($card) {
		cardIsOpen = true;
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;

		// Setup vars
		var cardId = $card.data('id');
		var cardIndex = $card.index();
		var siblingCardIndices = getRowIndices(cardIndex);
		var $siblingCards = $(getCards(siblingCardIndices).filter(function (card) {
			return card !== $card[0];
		}));
		var $otherCards = $tileCards.not($card).not($siblingCards);

		// Animate the contents of the clicked card
		$cardTiles.addClass('fullcard');
		openCardContent($card);

		// Animate the clicked card to open
		var $cardPadding = +$otherCards.css('padding').split('px')[0];
		var $cardHeight = $otherCards.height() + 2 * $cardPadding;
		$card.animate({
			width: OPEN_SIZE.WIDTH,
			height: OPEN_SIZE.HEIGHT
		}, {
			duration: animationTime,
			step: function (now, fx) {
				if (fx.prop === 'width') {
					var ratio = Math.max(0, Math.min(1, (now - CLOSED_SIZE.WIDTH)/(100 - CLOSED_SIZE.WIDTH)));
					var inverseRatio = 1 - ratio;

					resizing(cardId);
					var otherWidth = (100 - now) / 2;
					$siblingCards.css({
						width: otherWidth + '%'
					});

					if (inverseRatio < 0.05) {
						$otherCards.hide();
					}
					var otherHeight = inverseRatio * $cardHeight + 'px';
					var otherPadding = inverseRatio * $cardPadding + 'px';
					$otherCards.css({
						height: otherHeight,
						paddingTop: otherPadding,
						paddingBottom: otherPadding
					});
				}
			},
			done: function () {
				// Hide all cards
				$siblingCards.hide();
				$otherCards.hide();

				$card.removeClass('transitioning');
			}
		});

		// Animate the sibling cards on the same row to closed
		if ($siblingCards.length) {
			$siblingCards.each(function () {
				var $siblingCard = $(this);
				$(this).animate({
					// width: HIDE_SIZE.WIDTH,
					height: OPEN_SIZE.HEIGHT,
					paddingRight: 0,
					paddingLeft: 0
				}, animationTime, function () {
					$siblingCard.hide();
				});
			});
		}

		// Set some properties on the opened card
		$card.addClass('open transitioning');
		setNavButtonState();
	}

	function openCardContent ($card) {
		var cardId =$card.data('id');
		$card.find('.closed').show().fadeOut(ANIMATION_TIME);
		$card.find('.open').load('/api/card/' + cardId, function () {
			// Close button
			$('.closeButton').click(function () {
				closeCard($(this).closest('.card'));
				return false;
			});
		});
	}

	/**
	 * Closes a card.
	 * @param {Card} $card The jquery-wrapped card
	 */
	function closeCard ($card, horizontally) {
		// Setup vars
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;
		var cardId = $card.data('id');
		var cardIndex = $card.index();
		var siblingCardIndices = getRowIndices(cardIndex);
		var $siblingCards = $(getCards(siblingCardIndices)).not($card);
		var $otherRowCards = $tileCards.not($siblingCards).not($card);

		// Animate the clicked card to closed
		$card.animate({
			width: CLOSED_SIZE.WIDTH + '%',
			height: CLOSED_SIZE.HEIGHT + '%'
		}, {
			duration: animationTime,
			step: function (now, fx) {
				if (fx.prop === 'width') {
					var otherWidth = (100 - now) / 2;
					$siblingCards.css({
						width: otherWidth + '%'
					});
				}
			},
			done: function () {
				// Say card is open after all transitions are done
				cardIsOpen = false;
				$card.find('.open').html('');
				$card.removeClass('transitioning');
			}
		});

		// Animate the contents of the clicked card
		$cardTiles.removeClass('fullcard');
		$card.find('.closed').hide().fadeIn(animationTime);

		// Animate the sibling cards on the same row to closed
		if ($siblingCards.length) {
			$siblingCards.each(function () {
				var $siblingCard = $(this);
				$siblingCard.show().animate({
					height: CLOSED_SIZE.HEIGHT + '%',
					padding: CARD_PADDING
				}, {
					duration: animationTime,
				});
			});
		}

		// Animate other row cards
		$otherRowCards.each(function () {
			$(this).show().animate({
				width: CLOSED_SIZE.WIDTH + '%',
				height: CLOSED_SIZE.HEIGHT + '%',
				padding: CARD_PADDING
			}, {
				duration: animationTime
			});
		});

		$card.addClass('transitioning');
		$card.removeClass('open');
	}

	/**
	 * Navigates an open card to the project on the left
	 */
	function navLeft () {
		navSibling('left');
	}

	/**
	 * Navigates an open card to the project on the right
	 */
	function navRight () {
		navSibling('right');
	}

	function navSibling (direction) {
		var $openCard = $tileCards.filter('.open');
		var $siblingCard;
		switch (direction) {
			case 'left':
				$siblingCard = $openCard.prev();
				break;
			case 'right':
				$siblingCard = $openCard.next();
				break;
		}
		if ($siblingCard.length !== 0) {
			shiftCard($openCard, $siblingCard);
		}
		setNavButtonState();
	}

	function shiftCard ($cardClose, $cardOpen) {
		var cardCloseId = $cardClose.data('id');
		var cardOpenId = $cardOpen.data('id');
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;

		// Close card
		$cardClose.css({width:'95%'}).animate({
			paddingRight: 0,
			paddingLeft: 0,
			width: HIDE_SIZE.WIDTH
		}, {
			duration: animationTime/1.01,
			step: function () {
				resizing(cardCloseId);
			},
			done: function () {
				// Reset card
				$cardClose.hide().css({
					padding: CARD_PADDING
				}).find('.open').html('');
				$cardClose.find('.closed').show();
			}
		});
		$cardClose.removeClass('open');

		// Open card
		openCardContent($cardOpen);
		$cardOpen.find('.closed').hide();
		$cardOpen.css({
			display: 'inline-block',
			height: OPEN_SIZE.HEIGHT,
			width: HIDE_SIZE.WIDTH,
			padding: CARD_PADDING
		}).animate({
			width: OPEN_SIZE.WIDTH
		}, {
			duration: animationTime,
			step: function () {
				resizing(cardOpenId);
			},
			done: function () {
				$cardClose.hide();
			}
		});
		$cardOpen.addClass('open');

	}

	//
	// Helper functions
	//

	/**
	 * Gets an array of the indices of a certain row
	 * @param {Integer} cardIndex An index of a card to get the row from
	 * @returns {Integer[]} An array containing all the card indices of the specified row
	 */
	function getRowIndices(cardIndex) {
		var rowNum = Math.ceil((cardIndex + 1)/CARDS_PER_ROW) - 1;
		var colIndices = new Array(CARDS_PER_ROW);
		for (var i = 0; i < CARDS_PER_ROW; ++i) {
			colIndices[i] = rowNum * CARDS_PER_ROW + i;
		}
		return colIndices;
	}

	/**
	 * Gets the cards of a certain index or indices
	 * @param {Integer|Integer[]} indices The index/indices to get
	 * @returns {Card|Cards[]} The jquery-wrapped Card(s)
	 */
	function getCards (indices) {
		if (typeof indices === 'number') {
			return $tileCards[indices];
		} else { // Assume it's an array
			return indices.map(function(i) {
				return $tileCards[i];
			}).filter(function ($card) {
				// Removed cards that are falsey (ex. undefined)
				return !!$card;
			});
		}
	}

	/**
	 * Sets the state of teh nav buttons
	 */
	function setNavButtonState () {
		var $openCard = $tileCards.filter('.open');
		var $prev = $openCard.prev();
		var $next = $openCard.next();
		$openCard.find('.paginate.left').attr('data-state', $prev.length === 0 ? 'disabled' : '');
		$openCard.find('.paginate.right').attr('data-state', $next.length === 0 ? 'disabled' : '');
	}

	/**
	 * Sets the data from github for the github card's stats
	 */
	function setGithubData () {
		$.ajax({
			url: "https://api.github.com/users/grant"
		}).done(function (data) {
			var $githubCard = $('.card.github');
			$githubCard.find('.followers .statCount').html(data.followers);
			$githubCard.find('.following .statCount').html(data.following);
			$githubCard.find('.repos .statCount').html(data.public_repos);
		});
	}
});<commit_msg>Fixed #29<commit_after>$(function() {
	// TODO: Put constants somwhere
	var CARD_PADDING = '1.0%';
	var CARDS_PER_ROW = 3;
	var ANIMATION_TIME = 500;

	var OPEN_SIZE = {
		WIDTH: '100%',
		HEIGHT: '100%'
	};
	var CLOSED_SIZE = {
		WIDTH: 33.3,
		HEIGHT: (100/2.2)
	};
	var HIDE_SIZE = {
		WIDTH: '0%',
		HEIGHT: '0%'
	};

	// Page state variables
	var cardIsOpen = false;
	var $cardTiles = $('div.cardTiles');
	var $tileCards = $cardTiles.find('div.card');
	var numCards = $tileCards.length;
	var fitTexts = {
		'profile': [],
		'thefourelements': []
	};
	var shiftKey = false;

	// On load
	(function () {
		// Populate the fitText fields
		fitTexts['profile'].push(
			$('.profile .profileText .name').fitText(1.3),
			$('.profile .profileText .bio').fitText(3),
			$('.profile .closeButton .content').fitText(0.2),
			$('.profile .twitterHandle').fitText(7),
			$('.profile .longBio').fitText(7),
			$('.profile .experienceList .description').fitText(6),
			$('.profile .experienceList .descriptionBullets').fitText(6)
		);
		fitTexts['thefourelements'].push(
			$('.thefourelements .name').fitText(1.1),
			$('.thefourelements .description').fitText(2),
			$('.thefourelements .instructions').fitText(2),
			$('.thefourelements .plays').fitText(3)
		);

		// Resizes the profile video on window resize
		$(window).on('resize orientationchange', function () {
			// TODO: Make this happen only if the profile card is open
			resizeProfileVideo();
			resizeFlash();
		});

		// If you click outside the card, it automatically closes the opened card
		$('.cardArea').click(function (event) {
			var target = event.target;
			if ($(target).hasClass('card')) {
				closeCard($('.card.open'));
				return false;
			}
		});

		// Clicking on the nav buttons
		$('.paginate.left').click(navLeft);
		$('.paginate.right').click(navRight);

		// Github
		// setGithubData();
	})();

	//
	// Events
	//

	/**
	 * When clickcing on a card, open it up.
	 */
	$tileCards.click(function() {
		if (!cardIsOpen) {
			var $card = $(this);
			openCard($card);
			return false;
		}
	});

	// Check for shift key
	$(window).keydown(function (event) {
		shiftKey = event.shiftKey;
	});
	$(window).keyup(function (event) {
		shiftKey = event.shiftKey;
	});

	/**
	 * Called during steps of a card resizing
	 * @param {String} cardId The id of the card that is being resized
	 */
	function resizing (cardId) {
		fitTexts[cardId] = fitTexts[cardId] || [];
		fitTexts[cardId].forEach(function (resize) {
			resize();
		});

		// Special resizing cards
		switch (cardId) {
			case 'profile':
				resizeProfileVideo();
				break;
			case 'thefourelements':
				resizeFlash();
				break;
		}
	}

	/**
	 * Resizes the profile video and adjusts the position to cover the parent area
	 */
	function resizeProfileVideo() {
		// Resize video
		var $video = $('.profileVideo');
		var videoWidth = $video.width();
		var videoHeight = $video.height();

		var $videoArea = $video.parent();
		var videoAreaHeight = $videoArea.height();
		var videoAreaWidth = $videoArea.width();

		var videoRatio = videoWidth/videoHeight;
		var videoAreaRatio = videoAreaWidth/videoAreaHeight;

		var margin;
		// If videoArea too flat, make 100% height
		if (videoAreaRatio < videoRatio) {
			margin = (videoAreaWidth - videoWidth)/2;
			$video.css({
				'width': 'auto',
				'height': '100%',
				'margin-top': 0,
				'margin-left': margin
			});
		} else {
			margin = (videoAreaHeight - videoHeight)/2;
			$video.css({
				'width': '100%',
				'height': 'auto',
				'margin-top': margin,
				'margin-left': 0
			});
		}
	}

	/**
	 * Resizes the flash game to fit it (not cover) the parent area
	 */
	function resizeFlash () {
		var $swf = $('.thefourelements .swf');
		if ($swf.length) {
			var $parent = $swf.parent();
			var parentWidth = $parent.width();
			var parentHeight = $parent.height();

			var swfRatio = $swf.data('aspectratio');
			swfRatio = +swfRatio.split(':')[0]/+swfRatio.split(':')[1];
			var parentRatio = parentWidth/parentHeight;

			var margin = 0;
			if (swfRatio < parentRatio) {
				// Use 100% height
				var width = parentHeight * swfRatio;
				margin = (parentWidth - width)/2;
				$swf.css({
					'width': width + 'px',
					'height': '100%',
					'margin-top': 0,
					'margin-left': margin
				});
			} else {
				// Use 100% width
				var height = parentWidth/swfRatio;
				margin = (parentHeight - height)/2;
				$swf.css({
					'width': '100%',
					'height': height + 'px',
					'margin-top': margin,
					'margin-left': 0
				});
			}
		}
	}

	//
	// Actions
	//

	/**
	 * Opens a card. Expands it to fill the view
	 * @param {Card} $card The jquery-wrapped card
	 */
	function openCard ($card) {
		cardIsOpen = true;
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;

		// Setup vars
		var cardId = $card.data('id');
		var cardIndex = $card.index();
		var siblingCardIndices = getRowIndices(cardIndex);
		var $siblingCards = $(getCards(siblingCardIndices).filter(function (card) {
			return card !== $card[0];
		}));
		var $otherCards = $tileCards.not($card).not($siblingCards);

		// Animate the contents of the clicked card
		$cardTiles.addClass('fullcard');
		openCardContent($card);

		// Animate the clicked card to open
		var $cardPadding = +$otherCards.css('padding').split('px')[0];
		var $cardHeight = $otherCards.height() + 2 * $cardPadding;
		$card.animate({
			width: OPEN_SIZE.WIDTH,
			height: OPEN_SIZE.HEIGHT
		}, {
			duration: animationTime,
			step: function (now, fx) {
				if (fx.prop === 'width') {
					var ratio = Math.max(0, Math.min(1, (now - CLOSED_SIZE.WIDTH)/(100 - CLOSED_SIZE.WIDTH)));
					var inverseRatio = 1 - ratio;

					resizing(cardId);
					var otherWidth = (100 - now) / 2;
					$siblingCards.css({
						width: otherWidth + '%'
					});

					if (inverseRatio < 0.05) {
						$otherCards.hide();
					}
					var otherHeight = inverseRatio * $cardHeight + 'px';
					var otherPadding = inverseRatio * $cardPadding + 'px';
					$otherCards.css({
						height: otherHeight,
						paddingTop: otherPadding,
						paddingBottom: otherPadding
					});
				}
			},
			done: function () {
				// Hide all cards
				$siblingCards.hide();
				$otherCards.hide();

				$card.removeClass('transitioning');
			}
		});

		// Animate the sibling cards on the same row to closed
		if ($siblingCards.length) {
			$siblingCards.each(function () {
				var $siblingCard = $(this);
				$(this).animate({
					// width: HIDE_SIZE.WIDTH,
					height: OPEN_SIZE.HEIGHT,
					paddingRight: 0,
					paddingLeft: 0
				}, animationTime, function () {
					$siblingCard.hide();
				});
			});
		}

		// Set some properties on the opened card
		$card.addClass('open transitioning');
		setNavButtonState();
	}

	function openCardContent ($card) {
		var cardId =$card.data('id');
		$card.find('.closed').show().fadeOut(ANIMATION_TIME);
		$card.find('.open').load('/api/card/' + cardId, function () {
			// Close button
			$('.closeButton').click(function () {
				closeCard($(this).closest('.card'));
				return false;
			});
		});
	}

	/**
	 * Closes a card.
	 * @param {Card} $card The jquery-wrapped card
	 */
	function closeCard ($card, horizontally) {
		// Setup vars
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;
		var cardId = $card.data('id');
		var cardIndex = $card.index();
		var siblingCardIndices = getRowIndices(cardIndex);
		var $siblingCards = $(getCards(siblingCardIndices)).not($card);
		var $otherRowCards = $tileCards.not($siblingCards).not($card);

		// Animate the clicked card to closed
		$card.animate({
			width: CLOSED_SIZE.WIDTH + '%',
			height: CLOSED_SIZE.HEIGHT + '%'
		}, {
			duration: animationTime,
			step: function (now, fx) {
				if (fx.prop === 'width') {
					var otherWidth = (100 - now) / 2;
					$siblingCards.css({
						width: otherWidth + '%'
					});
				}
			},
			done: function () {
				// Say card is open after all transitions are done
				cardIsOpen = false;
				$card.find('.open').html('');
				$card.removeClass('transitioning');
			}
		});

		// Animate the contents of the clicked card
		$cardTiles.removeClass('fullcard');
		$card.find('.closed').hide().fadeIn(animationTime);

		// Animate the sibling cards on the same row to closed
		if ($siblingCards.length) {
			$siblingCards.each(function () {
				var $siblingCard = $(this);
				$siblingCard.show().animate({
					height: CLOSED_SIZE.HEIGHT + '%',
					padding: CARD_PADDING
				}, {
					duration: animationTime,
				});
			});
		}

		// Animate other row cards
		$otherRowCards.each(function () {
			$(this).show().animate({
				width: CLOSED_SIZE.WIDTH + '%',
				height: CLOSED_SIZE.HEIGHT + '%',
				padding: CARD_PADDING
			}, {
				duration: animationTime
			});
		});

		$card.addClass('transitioning');
		$card.removeClass('open');
	}

	/**
	 * Navigates an open card to the project on the left
	 */
	function navLeft () {
		navSibling('left');
	}

	/**
	 * Navigates an open card to the project on the right
	 */
	function navRight () {
		navSibling('right');
	}

	function navSibling (direction) {
		var $openCard = $tileCards.filter('.open');
		var $siblingCard;
		switch (direction) {
			case 'left':
				$siblingCard = $openCard.prev();
				break;
			case 'right':
				$siblingCard = $openCard.next();
				break;
		}
		if ($siblingCard.length !== 0) {
			shiftCard($openCard, $siblingCard);
		}
		setNavButtonState();
	}

	function shiftCard ($cardClose, $cardOpen) {
		var cardCloseId = $cardClose.data('id');
		var cardOpenId = $cardOpen.data('id');
		var animationTime = (shiftKey) ? ANIMATION_TIME * 10 : ANIMATION_TIME;

		// Close card
		$cardClose.css({width:'95%'}).animate({
			paddingRight: 0,
			paddingLeft: 0,
			width: HIDE_SIZE.WIDTH
		}, {
			duration: animationTime/1.01,
			step: function () {
				resizing(cardCloseId);
			},
			done: function () {
				// Reset card
				$cardClose.hide().css({
					padding: CARD_PADDING
				}).find('.open').html('');
				$cardClose.find('.closed').show();
			}
		});
		$cardClose.removeClass('open');

		// Open card
		openCardContent($cardOpen);
		$cardOpen.find('.closed').hide();
		$cardOpen.css({
			display: 'inline-block',
			height: OPEN_SIZE.HEIGHT,
			width: HIDE_SIZE.WIDTH,
			padding: CARD_PADDING
		}).animate({
			width: OPEN_SIZE.WIDTH
		}, {
			duration: animationTime,
			step: function () {
				resizing(cardOpenId);
			},
			done: function () {
				$cardClose.hide();
			}
		});
		$cardOpen.addClass('open');

	}

	//
	// Helper functions
	//

	/**
	 * Gets an array of the indices of a certain row
	 * @param {Integer} cardIndex An index of a card to get the row from
	 * @returns {Integer[]} An array containing all the card indices of the specified row
	 */
	function getRowIndices(cardIndex) {
		var rowNum = Math.ceil((cardIndex + 1)/CARDS_PER_ROW) - 1;
		var colIndices = new Array(CARDS_PER_ROW);
		for (var i = 0; i < CARDS_PER_ROW; ++i) {
			colIndices[i] = rowNum * CARDS_PER_ROW + i;
		}
		return colIndices;
	}

	/**
	 * Gets the cards of a certain index or indices
	 * @param {Integer|Integer[]} indices The index/indices to get
	 * @returns {Card|Cards[]} The jquery-wrapped Card(s)
	 */
	function getCards (indices) {
		if (typeof indices === 'number') {
			return $tileCards[indices];
		} else { // Assume it's an array
			return indices.map(function(i) {
				return $tileCards[i];
			}).filter(function ($card) {
				// Removed cards that are falsey (ex. undefined)
				return !!$card;
			});
		}
	}

	/**
	 * Sets the state of teh nav buttons
	 */
	function setNavButtonState () {
		var $openCard = $tileCards.filter('.open');
		var $prev = $openCard.prev();
		var $next = $openCard.next();
		$openCard.find('.paginate.left').attr('data-state', $prev.length === 0 ? 'disabled' : '');
		$openCard.find('.paginate.right').attr('data-state', $next.length === 0 ? 'disabled' : '');
	}

	/**
	 * Sets the data from github for the github card's stats
	 */
	function setGithubData () {
		$.ajax({
			url: "https://api.github.com/users/grant"
		}).done(function (data) {
			var $githubCard = $('.card.github');
			$githubCard.find('.followers .statCount').html(data.followers);
			$githubCard.find('.following .statCount').html(data.following);
			$githubCard.find('.repos .statCount').html(data.public_repos);
		});
	}
});<|endoftext|>


<commit_before>if (typeof(jQuery) === 'undefined') {
	throw('Unable to find jQuery');
}

if (typeof(chordsWiki) === 'undefined') {
	var chordsWiki = {};
}

(function() {
	'use strict';

	chordsWiki.Main = function() {

		var self = this;

		this.container = $('<div>');

		var chordSelect = $('<select>');

		var categorySelect = $('<select>');

		var init = function() {
			render();
			$('body').append(self.container);
		};

		var render = function() {

			//East area creation
			var eastContainer = $('<div>');
			eastContainer.addClass('east_area');
			var subtitleEast = $('<h2>');
			subtitleEast.text('Chord selection');
			eastContainer.append(subtitleEast);
			eastContainer.append(chordSelect);
			eastContainer.append(categorySelect);

			//West area creation
			var westContainer = $('<div>');
			westContainer.addClass('west_area');
			var subtitleWest = $('<h2>');
			subtitleWest.text('Chord details');
			westContainer.append(subtitleWest);

			//Main content wrapper creation
			var mainContent = $('<main>');
			mainContent.append(eastContainer);
			mainContent.append(westContainer);

			//Append to container
			self.container.append(mainContent);

		};

		init();

	};

}());<commit_msg>CONST variable added<commit_after>if (typeof(jQuery) === 'undefined') {
	throw('Unable to find jQuery');
}

if (typeof(chordsWiki) === 'undefined') {
	var chordsWiki = {};
}

(function() {
	'use strict';

	chordsWiki.Main = function() {

		var CONST = {
			CSS: {
				EAST_AREA: 'east_area',
				WEST_AREA: 'west_area'
			},
			STRING: {
				SUBTITLE_EAST: 'Chord selection',
				SUBTITLE_WEST: 'Chord details'
			}
		};

		var self = this;

		this.container = $('<div>');

		var chordSelect = $('<select>');

		var categorySelect = $('<select>');

		var init = function() {
			render();
			$('body').append(self.container);
		};

		var render = function() {

			//East area creation
			var eastContainer = $('<div>');
			eastContainer.addClass(CONST.CSS.EAST_AREA);
			var subtitleEast = $('<h2>');
			subtitleEast.text(CONST.STRING.SUBTITLE_EAST);
			eastContainer.append(subtitleEast);
			eastContainer.append(chordSelect);
			eastContainer.append(categorySelect);

			//West area creation
			var westContainer = $('<div>');
			westContainer.addClass(CONST.CSS.WEST_AREA);
			var subtitleWest = $('<h2>');
			subtitleWest.text(CONST.STRING.SUBTITLE_WEST);
			westContainer.append(subtitleWest);

			//Main content wrapper creation
			var mainContent = $('<main>');
			mainContent.append(eastContainer);
			mainContent.append(westContainer);

			//Append to container
			self.container.append(mainContent);

		};

		init();

	};

}());<|endoftext|>