<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import RandomPollButton from './RandomPollButton';

class DashboardNoPolls extends Component {

  constructor(props){
    super(props);
    this.randomPollButtonClicked = this.randomPollButtonClicked.bind(this);
    this.state = {
      fireRedirect : false,
      redirectId: null
    }
  }

  randomPollButtonClicked(id){
    this.setState({
      fireRedirect : true,
      redirectId: id
    });
  }

  render(){
    let currentUser = localStorage.getItem("currentUser");
    return (

{currentUser}, welcome to your dashboard.
            You have no polls yet.

<Link to="/new">New Poll</Link>

            <RandomPollButton handleClick={this.randomPollButtonClicked}/>

        {this.state.fireRedirect && this.state.redirectId && (
          <Redirect to={`/polls/${this.state.redirectId}`}
        )}

    );
  }
}

export default DashboardNoPolls;
<commit_msg>import Redirect<commit_after>import React, { Component } from 'react';
import { Link, Redirect } from 'react-router-dom';
import RandomPollButton from './RandomPollButton';

class DashboardNoPolls extends Component {

  constructor(props){
    super(props);
    this.randomPollButtonClicked = this.randomPollButtonClicked.bind(this);
    this.state = {
      fireRedirect : false,
      redirectId: null
    }
  }

  randomPollButtonClicked(id){
    this.setState({
      fireRedirect : true,
      redirectId: id
    });
  }

  render(){
    let currentUser = localStorage.getItem("currentUser");
    return (

{currentUser}, welcome to your dashboard.
            You have no polls yet.

<Link to="/new">New Poll</Link>

            <RandomPollButton handleClick={this.randomPollButtonClicked}/>

        {this.state.fireRedirect && this.state.redirectId && (
          <Redirect to={`/polls/${this.state.redirectId}`}
        )}

    );
  }
}

export default DashboardNoPolls;
<|endoftext|>


<commit_before>import styled from 'styled-components';
import { display, space, width, alignItems, minHeight, justifyContent, flexDirection } from 'styled-system';

export default styled.div`
  ${display}
  ${width}
  ${minHeight}
  ${space}
  ${alignItems}
  ${justifyContent}
  ${flexDirection}
`;
<commit_msg>Mixin more powers<commit_after>import styled from 'styled-components';
import {
  display,
  space,
  width,
  height,
  alignItems,
  minHeight,
  justifyContent,
  flexDirection,
  border,
} from 'styled-system';

export default styled.div`
  box-sizing: border-box;
  ${display}
  ${width}
  ${height}
  ${minHeight}
  ${space}
  ${alignItems}
  ${justifyContent}
  ${flexDirection}
  ${border}
`;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const {utils: Cu} = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "LogManager",
  "resource://shield-recipe-client/lib/LogManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShieldRecipeClient",
  "resource://shield-recipe-client/lib/ShieldRecipeClient.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PreferenceExperiments",
  "resource://shield-recipe-client/lib/PreferenceExperiments.jsm");

// Act as both a normal bootstrap.js and a JS module so that we can test
// startup methods without having to install/uninstall the add-on.
this.EXPORTED_SYMBOLS = ["Bootstrap"];

const REASON_APP_STARTUP = 1;
const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
const STARTUP_EXPERIMENT_PREFS_BRANCH = "extensions.shield-recipe-client.startupExperimentPrefs.";
const PREF_LOGGING_LEVEL = "extensions.shield-recipe-client.logging.level";
const BOOTSTRAP_LOGGER_NAME = "extensions.shield-recipe-client.bootstrap";
const DEFAULT_PREFS = {
  "extensions.shield-recipe-client.api_url": "https://normandy.cdn.mozilla.net/api/v1",
  "extensions.shield-recipe-client.dev_mode": false,
  "extensions.shield-recipe-client.enabled": true,
  "extensions.shield-recipe-client.startup_delay_seconds": 300,
  "extensions.shield-recipe-client.logging.level": Log.Level.Warn,
  "extensions.shield-recipe-client.user_id": "",
  "extensions.shield-recipe-client.run_interval_seconds": 86400, // 24 hours
  "extensions.shield-recipe-client.first_run": true,
  "extensions.shield-recipe-client.shieldLearnMoreUrl": (
    "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/shield"
  ),
  "app.shield.optoutstudies.enabled": AppConstants.MOZ_DATA_REPORTING,
};

// Logging
const log = Log.repository.getLogger(BOOTSTRAP_LOGGER_NAME);
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
log.level = Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn);

let studyPrefsChanged = {};

this.Bootstrap = {
  initShieldPrefs(defaultPrefs) {
    const prefBranch = Services.prefs.getDefaultBranch("");
    for (const [name, value] of Object.entries(defaultPrefs)) {
      switch (typeof value) {
        case "string":
          prefBranch.setCharPref(name, value);
          break;
        case "number":
          prefBranch.setIntPref(name, value);
          break;
        case "boolean":
          prefBranch.setBoolPref(name, value);
          break;
        default:
          throw new Error(`Invalid default preference type ${typeof value}`);
      }
    }
  },

  initExperimentPrefs() {
    const defaultBranch = Services.prefs.getDefaultBranch("");
    const experimentBranch = Services.prefs.getBranch(STARTUP_EXPERIMENT_PREFS_BRANCH);

    for (const prefName of experimentBranch.getChildList("")) {
      const experimentPrefType = experimentBranch.getPrefType(prefName);
      const realPrefType = defaultBranch.getPrefType(prefName);

      if (realPrefType !== Services.prefs.PREF_INVALID && realPrefType !== experimentPrefType) {
        log.error(`Error setting startup pref ${prefName}; pref type does not match.`);
        continue;
      }

      switch (experimentPrefType) {
        case Services.prefs.PREF_STRING:
          studyPrefsChanged[prefName] = defaultBranch.getCharPref(prefName, undefined);
          defaultBranch.setCharPref(prefName, experimentBranch.getCharPref(prefName));
          break;

        case Services.prefs.PREF_INT:
          studyPrefsChanged[prefName] = defaultBranch.getIntPref(prefName, undefined);
          defaultBranch.setIntPref(prefName, experimentBranch.getIntPref(prefName));
          break;

        case Services.prefs.PREF_BOOL:
          studyPrefsChanged[prefName] = defaultBranch.getBoolPref(prefName, undefined);
          defaultBranch.setBoolPref(prefName, experimentBranch.getBoolPref(prefName));
          break;

        case Services.prefs.PREF_INVALID:
          // This should never happen.
          log.error(`Error setting startup pref ${prefName}; pref type is invalid (${experimentPrefType}).`);
          break;

        default:
          // This should never happen either.
          log.error(`Error getting startup pref ${prefName}; unknown value type ${experimentPrefType}.`);
      }
    }
  },

  observe(subject, topic, data) {
    if (topic === UI_AVAILABLE_NOTIFICATION) {
      Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
      this.finishStartup();
    }
  },

  install() {
    // Nothing to do during install
  },

  startup(data, reason) {
    // Initialization that needs to happen before the first paint on startup.
    this.initShieldPrefs(DEFAULT_PREFS);
    this.initExperimentPrefs();

    // If the app is starting up, wait until the UI is available before finishing
    // init.
    if (reason === REASON_APP_STARTUP) {
      Services.obs.addObserver(this, UI_AVAILABLE_NOTIFICATION);
    } else {
      this.finishStartup();
    }
  },

  async finishStartup() {
    await PreferenceExperiments.recordOriginalValues(studyPrefsChanged);
    ShieldRecipeClient.startup();
  },

  async shutdown(data, reason) {
    // Wait for async write operations during shutdown before unloading modules.
    await ShieldRecipeClient.shutdown(reason);

    // In case the observer didn't run, clean it up.
    try {
      Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
    } catch (err) {
      // It must already be removed!
    }

    // Unload add-on modules. We don't do this in ShieldRecipeClient so that
    // modules are not unloaded accidentally during tests.
    let modules = [
      "lib/ActionSandboxManager.jsm",
      "lib/Addons.jsm",
      "lib/AddonStudies.jsm",
      "lib/CleanupManager.jsm",
      "lib/ClientEnvironment.jsm",
      "lib/FilterExpressions.jsm",
      "lib/EventEmitter.jsm",
      "lib/Heartbeat.jsm",
      "lib/LogManager.jsm",
      "lib/NormandyApi.jsm",
      "lib/NormandyDriver.jsm",
      "lib/PreferenceExperiments.jsm",
      "lib/RecipeRunner.jsm",
      "lib/Sampling.jsm",
      "lib/SandboxManager.jsm",
      "lib/ShieldPreferences.jsm",
      "lib/ShieldRecipeClient.jsm",
      "lib/Storage.jsm",
      "lib/Uptake.jsm",
      "lib/Utils.jsm",
    ].map(m => `resource://shield-recipe-client/${m}`);
    modules = modules.concat([
      "resource://shield-recipe-client-content/AboutPages.jsm",
      "resource://shield-recipe-client-vendor/mozjexl.js",
    ]);

    for (const module of modules) {
      log.debug(`Unloading ${module}`);
      Cu.unload(module);
    }
  },

  uninstall() {
    // Do nothing
  },
};

// Expose bootstrap methods on the global
for (const methodName of ["install", "startup", "shutdown", "uninstall"]) {
  this[methodName] = Bootstrap[methodName].bind(Bootstrap);
}
<commit_msg>Defaults for `get*Pref` can't be undefined, so use try-catch.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const {utils: Cu} = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "LogManager",
  "resource://shield-recipe-client/lib/LogManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ShieldRecipeClient",
  "resource://shield-recipe-client/lib/ShieldRecipeClient.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PreferenceExperiments",
  "resource://shield-recipe-client/lib/PreferenceExperiments.jsm");

// Act as both a normal bootstrap.js and a JS module so that we can test
// startup methods without having to install/uninstall the add-on.
this.EXPORTED_SYMBOLS = ["Bootstrap"];

const REASON_APP_STARTUP = 1;
const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
const STARTUP_EXPERIMENT_PREFS_BRANCH = "extensions.shield-recipe-client.startupExperimentPrefs.";
const PREF_LOGGING_LEVEL = "extensions.shield-recipe-client.logging.level";
const BOOTSTRAP_LOGGER_NAME = "extensions.shield-recipe-client.bootstrap";
const DEFAULT_PREFS = {
  "extensions.shield-recipe-client.api_url": "https://normandy.cdn.mozilla.net/api/v1",
  "extensions.shield-recipe-client.dev_mode": false,
  "extensions.shield-recipe-client.enabled": true,
  "extensions.shield-recipe-client.startup_delay_seconds": 300,
  "extensions.shield-recipe-client.logging.level": Log.Level.Warn,
  "extensions.shield-recipe-client.user_id": "",
  "extensions.shield-recipe-client.run_interval_seconds": 86400, // 24 hours
  "extensions.shield-recipe-client.first_run": true,
  "extensions.shield-recipe-client.shieldLearnMoreUrl": (
    "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/shield"
  ),
  "app.shield.optoutstudies.enabled": AppConstants.MOZ_DATA_REPORTING,
};

// Logging
const log = Log.repository.getLogger(BOOTSTRAP_LOGGER_NAME);
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
log.level = Services.prefs.getIntPref(PREF_LOGGING_LEVEL, Log.Level.Warn);

let studyPrefsChanged = {};

this.Bootstrap = {
  initShieldPrefs(defaultPrefs) {
    const prefBranch = Services.prefs.getDefaultBranch("");
    for (const [name, value] of Object.entries(defaultPrefs)) {
      switch (typeof value) {
        case "string":
          prefBranch.setCharPref(name, value);
          break;
        case "number":
          prefBranch.setIntPref(name, value);
          break;
        case "boolean":
          prefBranch.setBoolPref(name, value);
          break;
        default:
          throw new Error(`Invalid default preference type ${typeof value}`);
      }
    }
  },

  initExperimentPrefs() {
    const defaultBranch = Services.prefs.getDefaultBranch("");
    const experimentBranch = Services.prefs.getBranch(STARTUP_EXPERIMENT_PREFS_BRANCH);

    for (const prefName of experimentBranch.getChildList("")) {
      const experimentPrefType = experimentBranch.getPrefType(prefName);
      const realPrefType = defaultBranch.getPrefType(prefName);

      if (realPrefType !== Services.prefs.PREF_INVALID && realPrefType !== experimentPrefType) {
        log.error(`Error setting startup pref ${prefName}; pref type does not match.`);
        continue;
      }

      switch (experimentPrefType) {
        case Services.prefs.PREF_STRING:
          try {  // eslint-disable-line mozilla/use-default-preference-values
            studyPrefsChanged[prefName] = defaultBranch.getCharPref(prefName);
          } catch (e) {
            Cu.reportError(e);
          }
          defaultBranch.setCharPref(prefName, experimentBranch.getCharPref(prefName));
          break;

        case Services.prefs.PREF_INT:
          try {  // eslint-disable-line mozilla/use-default-preference-values
            studyPrefsChanged[prefName] = defaultBranch.getIntPref(prefName);
          } catch (e) {
            Cu.reportError(e);
          }
          defaultBranch.setIntPref(prefName, experimentBranch.getIntPref(prefName));
          break;

        case Services.prefs.PREF_BOOL:
          try {  // eslint-disable-line mozilla/use-default-preference-values
            studyPrefsChanged[prefName] = defaultBranch.getBoolPref(prefName);
          } catch (e) {
            Cu.reportError(e);
          }
          defaultBranch.setBoolPref(prefName, experimentBranch.getBoolPref(prefName));
          break;

        case Services.prefs.PREF_INVALID:
          // This should never happen.
          log.error(`Error setting startup pref ${prefName}; pref type is invalid (${experimentPrefType}).`);
          break;

        default:
          // This should never happen either.
          log.error(`Error getting startup pref ${prefName}; unknown value type ${experimentPrefType}.`);
      }
    }
  },

  observe(subject, topic, data) {
    if (topic === UI_AVAILABLE_NOTIFICATION) {
      Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
      this.finishStartup();
    }
  },

  install() {
    // Nothing to do during install
  },

  startup(data, reason) {
    // Initialization that needs to happen before the first paint on startup.
    this.initShieldPrefs(DEFAULT_PREFS);
    this.initExperimentPrefs();

    // If the app is starting up, wait until the UI is available before finishing
    // init.
    if (reason === REASON_APP_STARTUP) {
      Services.obs.addObserver(this, UI_AVAILABLE_NOTIFICATION);
    } else {
      this.finishStartup();
    }
  },

  async finishStartup() {
    await PreferenceExperiments.recordOriginalValues(studyPrefsChanged);
    ShieldRecipeClient.startup();
  },

  async shutdown(data, reason) {
    // Wait for async write operations during shutdown before unloading modules.
    await ShieldRecipeClient.shutdown(reason);

    // In case the observer didn't run, clean it up.
    try {
      Services.obs.removeObserver(this, UI_AVAILABLE_NOTIFICATION);
    } catch (err) {
      // It must already be removed!
    }

    // Unload add-on modules. We don't do this in ShieldRecipeClient so that
    // modules are not unloaded accidentally during tests.
    let modules = [
      "lib/ActionSandboxManager.jsm",
      "lib/Addons.jsm",
      "lib/AddonStudies.jsm",
      "lib/CleanupManager.jsm",
      "lib/ClientEnvironment.jsm",
      "lib/FilterExpressions.jsm",
      "lib/EventEmitter.jsm",
      "lib/Heartbeat.jsm",
      "lib/LogManager.jsm",
      "lib/NormandyApi.jsm",
      "lib/NormandyDriver.jsm",
      "lib/PreferenceExperiments.jsm",
      "lib/RecipeRunner.jsm",
      "lib/Sampling.jsm",
      "lib/SandboxManager.jsm",
      "lib/ShieldPreferences.jsm",
      "lib/ShieldRecipeClient.jsm",
      "lib/Storage.jsm",
      "lib/Uptake.jsm",
      "lib/Utils.jsm",
    ].map(m => `resource://shield-recipe-client/${m}`);
    modules = modules.concat([
      "resource://shield-recipe-client-content/AboutPages.jsm",
      "resource://shield-recipe-client-vendor/mozjexl.js",
    ]);

    for (const module of modules) {
      log.debug(`Unloading ${module}`);
      Cu.unload(module);
    }
  },

  uninstall() {
    // Do nothing
  },
};

// Expose bootstrap methods on the global
for (const methodName of ["install", "startup", "shutdown", "uninstall"]) {
  this[methodName] = Bootstrap[methodName].bind(Bootstrap);
}
<|endoftext|>


<commit_before>export default '0.8.4';
<commit_msg>bump to 0.8.5<commit_after>export default '0.8.5';
<|endoftext|>


<commit_before>// #docregion
module.exports = function(config) {

  var appBase    = 'app/';       // transpiled app JS and map files
  var appSrcBase = 'app/';       // app source TS files
  var appAssets  = 'base/app/'; // component assets fetched by Angular's compiler

  var testBase    = 'testing/';       // transpiled test JS and map files
  var testSrcBase = 'testing/';       // test source TS files

  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'), // click "Debug" in browser to see it
      require('karma-htmlfile-reporter') // crashing w/ strange socket error
    ],

    customLaunchers: {
      // From the CLI. Not used here but interesting
      // chrome setup for travis CI using chromium
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    files: [
      // System.js for module loading
      'node_modules/systemjs/dist/system.src.js',

      // Polyfills
      'node_modules/core-js/client/shim.js',
      'node_modules/reflect-metadata/Reflect.js',

      // zone.js
      'node_modules/zone.js/dist/zone.js',
      'node_modules/zone.js/dist/long-stack-trace-zone.js',
      'node_modules/zone.js/dist/proxy.js',
      'node_modules/zone.js/dist/sync-test.js',
      'node_modules/zone.js/dist/jasmine-patch.js',
      'node_modules/zone.js/dist/async-test.js',
      'node_modules/zone.js/dist/fake-async-test.js',

      // RxJs
      { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
      { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },

      // Paths loaded via module imports:
      // Angular itself
      { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
      { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },

      { pattern: 'systemjs.config.js', included: false, watched: false },
      { pattern: 'systemjs.config.extras.js', included: false, watched: false },
      'karma-test-shim.js',

      // transpiled application & spec code paths loaded via module imports
      { pattern: appBase + '**/*.js', included: false, watched: true },
      { pattern: testBase + '**/*.js', included: false, watched: true },

      // Asset (HTML & CSS) paths loaded via Angular's component compiler
      // (these paths need to be rewritten, see proxies section)
      { pattern: appBase + '**/*.html', included: false, watched: true },
      { pattern: appBase + '**/*.css', included: false, watched: true },

      // Paths for debugging with source maps in dev tools
      { pattern: appSrcBase + '**/*.ts', included: false, watched: false },
      { pattern: appBase + '**/*.js.map', included: false, watched: false },
      { pattern: testSrcBase + '**/*.ts', included: false, watched: false },
      { pattern: testBase + '**/*.js.map', included: false, watched: false }
    ],

    // Proxied base paths for loading assets
    proxies: {
      // required for component assets fetched by Angular's compiler
      "/app/": appAssets
    },

    exclude: [],
    preprocessors: {},
    // disabled HtmlReporter; suddenly crashing w/ strange socket error
    reporters: ['progress', 'kjhtml'],//'html'],

    // HtmlReporter configuration
    htmlReporter: {
      // Open this file to see results in browser
      outputFile: '_test-output/tests.html',

      // Optional
      pageTitle: 'Unit Tests',
      subPageTitle: __dirname
    },

    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  })
}
<commit_msg>Update path of the transpiled app js and map file<commit_after>// #docregion
module.exports = function(config) {

  var appBase    = 'build/app/';       // transpiled app JS and map files
  var appSrcBase = 'app/';       // app source TS files
  var appAssets  = 'base/app/'; // component assets fetched by Angular's compiler

  var testBase    = 'testing/';       // transpiled test JS and map files
  var testSrcBase = 'testing/';       // test source TS files

  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'), // click "Debug" in browser to see it
      require('karma-htmlfile-reporter') // crashing w/ strange socket error
    ],

    customLaunchers: {
      // From the CLI. Not used here but interesting
      // chrome setup for travis CI using chromium
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    files: [
      // System.js for module loading
      'node_modules/systemjs/dist/system.src.js',

      // Polyfills
      'node_modules/core-js/client/shim.js',
      'node_modules/reflect-metadata/Reflect.js',

      // zone.js
      'node_modules/zone.js/dist/zone.js',
      'node_modules/zone.js/dist/long-stack-trace-zone.js',
      'node_modules/zone.js/dist/proxy.js',
      'node_modules/zone.js/dist/sync-test.js',
      'node_modules/zone.js/dist/jasmine-patch.js',
      'node_modules/zone.js/dist/async-test.js',
      'node_modules/zone.js/dist/fake-async-test.js',

      // RxJs
      { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
      { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },

      // Paths loaded via module imports:
      // Angular itself
      { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
      { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },

      { pattern: 'systemjs.config.js', included: false, watched: false },
      { pattern: 'systemjs.config.extras.js', included: false, watched: false },
      'karma-test-shim.js',

      // transpiled application & spec code paths loaded via module imports
      { pattern: appBase + '**/*.js', included: false, watched: true },
      { pattern: testBase + '**/*.js', included: false, watched: true },

      // Asset (HTML & CSS) paths loaded via Angular's component compiler
      // (these paths need to be rewritten, see proxies section)
      { pattern: appBase + '**/*.html', included: false, watched: true },
      { pattern: appBase + '**/*.css', included: false, watched: true },

      // Paths for debugging with source maps in dev tools
      { pattern: appSrcBase + '**/*.ts', included: false, watched: false },
      { pattern: appBase + '**/*.js.map', included: false, watched: false },
      { pattern: testSrcBase + '**/*.ts', included: false, watched: false },
      { pattern: testBase + '**/*.js.map', included: false, watched: false }
    ],

    // Proxied base paths for loading assets
    proxies: {
      // required for component assets fetched by Angular's compiler
      "/app/": appAssets
    },

    exclude: [],
    preprocessors: {},
    // disabled HtmlReporter; suddenly crashing w/ strange socket error
    reporters: ['progress', 'kjhtml'],//'html'],

    // HtmlReporter configuration
    htmlReporter: {
      // Open this file to see results in browser
      outputFile: '_test-output/tests.html',

      // Optional
      pageTitle: 'Unit Tests',
      subPageTitle: __dirname
    },

    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  })
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
    AppRegistry,
    Text,
    View,
    Image,
} from 'react-native';
import { observer } from 'mobx-react/native';
import { Container, Content, List } from 'native-base';
import styles from './styles.js';

@observer
export default class Ranking extends Component {

    constructor(props) {
        super(props);
    }

    async componentWillMount() {
        const { store: { ranking } } = this.props;

        await ranking.computePromotion({ refreshCache: false });
    }

    renderStudent(student) {
        return (

            <View style={styles.dataContainer}>
                <Text style={styles.rank}>{student.rank}</Text>
                <Image source={{uri: student.picture}} style={styles.picture} />
                <Text style={styles.mainText}>{student.title}{'\n'}{student.credits} credits</Text>
                <Image source={student.img} style={styles.flag} />
                <Text style={styles.gpaText}>{student.gpa[0].gpa}</Text>
            </View>
        )
    }

    renderSelf(student) {
        return (

            <View style={styles.selfDataContainer}>
                <Text style={styles.rank}>{student.rank}</Text>
                <Image source={{uri: student.picture}} style={styles.picture} />
                <Text style={styles.mainText}>{student.title}{'\n'}{student.credits} credits</Text>
                <Image source={student.img} style={styles.flag} />
                <Text style={styles.gpaText}>{student.gpa[0].gpa}</Text>
            </View>
        )
    }

    render() {
        const { store: { ranking } } = this.props;
        const selfRank = ranking.selfRank();

        if (!ranking.promotion.length) {
            return (
                <View>
                    <Text>Loading ranking. This may take a while...</Text>
                </View>
            );
        }

        return (
            <Container>
                <Content>
                    { this.renderSelf(selfRank) }
                    <List
                        dataArray={ranking.promotion.slice()}
                        renderRow={(student) => this.renderStudent(student)}>
                    </List>
                </Content>
            </Container>
        );
    }
}
<commit_msg>- Improved performance using native listview instead<commit_after>import React, { Component } from 'react';
import {
    AppRegistry,
    Text,
    View,
    Image,
    ListView,
} from 'react-native';
import { observer } from 'mobx-react/native';
import { Container, Content } from 'native-base';
import styles from './styles.js';

@observer
export default class Ranking extends Component {

    constructor(props) {
        super(props);

        this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    }

    async componentWillMount() {
        const { store: { ranking } } = this.props;

        await ranking.computePromotion({ refreshCache: false });
    }

    renderStudent(student) {
        return (

            <View style={styles.dataContainer}>
                <Text style={styles.rank}>{student.rank}</Text>
                <Image source={{uri: student.picture}} style={styles.picture} />
                <Text style={styles.mainText}>{student.title}{'\n'}{student.credits} credits</Text>
                <Image source={student.img} style={styles.flag} />
                <Text style={styles.gpaText}>{student.gpa[0].gpa}</Text>
            </View>
        )
    }

    renderSelf(student) {
        return (

            <View style={styles.selfDataContainer}>
                <Text style={styles.rank}>{student.rank}</Text>
                <Image source={{uri: student.picture}} style={styles.picture} />
                <Text style={styles.mainText}>{student.title}{'\n'}{student.credits} credits</Text>
                <Image source={student.img} style={styles.flag} />
                <Text style={styles.gpaText}>{student.gpa[0].gpa}</Text>
            </View>
        )
    }

    render() {
        const { store: { ranking } } = this.props;
        const selfRank = ranking.selfRank();

        if (!ranking.promotion.length) {
            return (
                <View>
                    <Text>Loading ranking. This may take a while...</Text>
                </View>
            );
        }

        return (
            <Container>
                <Content>
                    { this.renderSelf(selfRank) }
                    <ListView
                        style={styles.list}
                        dataSource={this.ds.cloneWithRows(ranking.promotion.slice())}
                        renderRow={this.renderStudent}
                    />
                </Content>
            </Container>
        );
    }
}
<|endoftext|>


<commit_before>var path = require('path'),
  config = require('./config'),
  alloy = require('./alloy'),
  component = require('./component'),
  dist = require('./dist'),
  tiapp = require('./tiapp'),
  exec = require('./exec'),
  rimraf = require('rimraf'),
  logger = require('./logger'),
  _ = require('underscore'),
  fs = require('fs-extended'),
  path = require('path'),
  utils = require('./utils'),
  async = require('async');

function uninstall(o) {

  if (o.version === '*') {
    delete o.version;
  }

  if (!_uninstallWidget(o)) {
    _uninstallModule(o);
  }
}

function _uninstallWidget(o) {
  if (config.context === 'global' || !fs.existsSync(config.widgets_path)) {
    return false;
  }
  var trgPath = path.join(config.widgets_path, o.id);
  var files = fs.readdirSync(config.widgets_path);
  var found = _.find(files, function(f) {
    return f === o.id;
  });
  var installed = found && (o.version === undefined || require(path.join(trgPath, 'widget.json')).version === o.version);
  var prefix = utils.prefix(o.id, o.version);
  if (installed) {
    rimraf.sync(trgPath);
    alloy.dropDependency(o.id, o.version);

    logger.info(prefix + ' uninstalled');

    return true;
  } else {
    found = _.find(files, function(f) {
      return f.toLowerCase() === o.id.toLowerCase();
    });
    if (found) {
      logger.error("Did you mean " + found + "?");
      return true;
    }
  }

  return false;
}

function _uninstallModule(o) {
  var trgPath = o.global ? config.global_modules_path : path.join(config.modules_path);
  var platform = (o.platform ? o.platform.replace("ios", "iphone") : undefined);
  var uninstalled = false;

  if (config.context === "project") {
    tiapp.dropDependency(o.id, o.version, platform);
  }

  if (o.global || config.context !== "project") {
    _.pairs(config.available_modules.global).forEach(function(kv) {
      var platform = kv[0],
        platform_modules = kv[1];
      if (o.platform === undefined || o.platform == platform) {
        _.pairs(platform_modules).forEach(function(kv) {
          var id = kv[0],
            id_modules = kv[1];
          if (o.id === id) {
            _.pairs(id_modules).forEach(function(kv) {
              var version = kv[0],
                module = kv[1];
              if (o.version === undefined || o.version === version) {
                var modulePath = path.join(module.modulePath);
                if (fs.existsSync(modulePath)) {
                  rimraf.sync(path.join(module.modulePath));
                  uninstalled = true;
                }
              }
            });
          }
        });
      }
    });
  } else {
    config.current_modules.map(function(m) {
      if (m.name === o.id &&
        (o.version === undefined || o.version === m.version) &&
        (platform === undefined || platform === m.platform)) {
        tiapp.dropDependency(o.id, o.version, platform);
        var modulePath = path.join(trgPath, m.platform, m.name);
        if (fs.existsSync(modulePath)) {
          rimraf.sync(modulePath);
          uninstalled = true;
        }
      }
    });
  }

  var prefix = utils.prefix(o.id, o.version);

  if (uninstalled) {
    logger.info(prefix + ' uninstalled');
  } else {
    logger.warn(prefix + ' not installed');
  }
}

function install(o) {

  if (o.version === '*') {
    delete o.version;
  }

  if (o.url) {
    return _installUrl(o.url, o);

  } else if (o.file) {
    return _installFile(o.file, o);

  } else if (o.id) {
    return _installSingle(o);

  } else {
    if (config.context === "global") {
      if (o.update && o.type !== "widget") {
        return _installAllModules(o);
      } else {
        logger.error("This command must be executed from a project directory");
        return;
      }
    }
    if (o.type === 'widget') {
      return _installAllWidgets(o);
    } else if (o.type === 'module') {
      return _installAllModules(o);
    } else {
      return _installAll(o);
    }
  }
}

function _addDependency(cmp, dst, o) {
  if (cmp.type === 'module' && config.context === 'project') {
    tiapp.addDependency(cmp.id, o.version, dst.platforms);
  } else if (cmp.type === 'widget') {
    alloy.addDependency(cmp.id, o.version);
  }
}

function findDown(dir, file) {

  if (fs.existsSync(path.join(dir, file))) {
    return file;
  }

  var files = fs.listAllSync(dir, {
    recursive: true,
    filter: function(itemPath, stat) {
      return (stat.isFile() && path.basename(itemPath) === file);
    }
  });

  if (files.length === 1) {
    return files[0];
  }

  return null;
}

function _installDir(dir, o) {

  var cmp = {};
  var dst = {};

  var widgetJson_path = findDown(dir, 'widget.json');

  if (widgetJson_path) {
    var widgetJson = require(path.join(dir, widgetJson_path));

    cmp.id = widgetJson.id;
    cmp.type = 'widget';

    dst.version = widgetJson.version;
    dst.srcPath = path.dirname(widgetJson_path);
    dst.trgPath = path.join(config.widgets_path, cmp.id);

  } else {

    var manifest_path = findDown(dir, 'manifest');

    if (!manifest_path) {
      logger.error('Cannot find a module manifest');
      return;
    }

    var manifest = fs.readFileSync(path.join(dir, manifest_path)).toString();
    var match;

    if (match = manifest.match(/^version: ?([^\n]+)$/m)) {
      dst.version = match[1];
    }

    if (match = manifest.match(/^moduleid: ?([^\n]+)$/m)) {
      cmp.id = match[1];

    } else {
      logger.error('Cannot find module id in the manifest');
      return;
    }

    if (match = manifest.match(/^platform(?:s)?: ?([^\n]+)$/m)) {
      dst.platforms = match[1].split(',');

    } else {
      logger.error('Cannot find target platforms in the manifest');
      return;
    }

    cmp.type = 'module';

    dst.srcPath = 'modules';
    dst.trgPath = o.global ? config.global_modules_path : config.modules_path;
  }

  var prefix = utils.prefix(cmp.id, dst.version, dst.platforms);

  // copy from tmpPath
  fs.copyDir(path.join(dir, dst.srcPath), dst.trgPath, function(err) {

    if (err) {
      logger.error(err);
      return;
    }

    // add dependency
    _addDependency(cmp, dst, o);

    // remove tmpPath
    rimraf.sync(dir);

    logger.info(prefix + ' installed');
  });
}

function _installUrl(url, o) {

  dist.download(url, function(err, dir) {

    if (err) {
      logger.error(err);
      return;
    }

    _installDir(dir, o);

  });
}

function _installFile(file, o) {

  dist.extract(file, function(err, dir) {

    if (err) {
      logger.error(err);
      return;
    }

    _installDir(dir, o);

  });
}

function _installSingle(o) {

  component.lookup(o.id, function(err, cmp) {

    if (err) {
      logger.error(err);
      return;
    }

    if (cmp.type === 'widget' && !config.isAlloy) {
      logger.error('Widgets must be installed within an Alloy project directory.');
      return;
    }

    // filter all dists
    var dists = component.filterDists(cmp, o);

    // nothing to install
    if (dists.length === 0) {
      return;
    }

    // for all dists
    _.each(dists, function(dst) {
      var prefix = utils.prefix(cmp.id, dst.version, dst.platforms),
        installed = dist.isInstalled(cmp, dst, o);

      // already installed
      if (installed && !o.force) {
        logger.warn(prefix + ' already installed');

        // add dependency
        _addDependency(cmp, dst, o);

      } else {

        // download
        logger.info(prefix + ' downloading...');

        dist.download(dst.dist, function(err, tmpPath) {

          if (err) {
            logger.error(err);
            return;
          }

          logger.info(prefix + ' installing...');

          // copy from tmpPath
          fs.copyDirSync(path.join(tmpPath, dst.srcPath), dst.trgPath);

          if (err) {
            logger.error(err);
            return;
          }

          // add dependency
          _addDependency(cmp, dst, o);

          // recursive widget dependencies
          if (cmp.type === 'widget') {
            var widget = require(path.join(dst.trgPath, 'widget.json'));

            // include our self-declared 'modules' dependencies
            var dependencies = _.extend({}, widget.dependencies || {}, widget.modules || {});

            if (_.size(dependencies) > 0) {
              var tasks = _.pairs(dependencies).map(function(kv) {
                var id = kv[0],
                  version = kv[1];

                return function() {
                  install(_.defaults({
                    id: id,
                    version: version
                  }, o));
                };

              });

              // install dependencies
              if (tasks.length > 0) {
                async.parallel(tasks);
              }
            }
          }

          // remove tmpPath
          rimraf.sync(tmpPath);

          logger.info(prefix + ' installed');
        });
      }
    });
  }, {
    action: o.update ? 'update' : 'install'
  });
}

function _installAll(o) {
  async.parallel([
    _.bind(_installAllWidgets, undefined, o),
    _.bind(_installAllModules, undefined, o)
  ]);
}

function _installAllWidgets(o) {

  if (config.isAlloy) {
    var data = config.alloy_config;

    if (data.dependencies && _.size(data.dependencies) > 0) {
      var tasks = [];

      _.each(data.dependencies, function(version, widget) {
        tasks.push(function() {
          install(_.extend({
            id: widget,
            version: o.update ? undefined : version
          }, o));
        });
      });

      async.parallel(tasks);

    } else {
      logger.warn('no widgets found to ' + (o.update ? 'update' : 'install'));
    }
  }
}

function _installAllModules(o) {
  var tasks;
  if (config.context === "project") {
    tasks = config.current_modules.map(function(m) {
      return function() {
        install(_.defaults({
          id: m.name,
          version: o.update ? undefined : m.version,
          platform: m.platform.replace("iphone", "ios")
        }, o));
      };
    });
  } else {
    tasks = [];
    _.pairs(config.available_modules.global).forEach(function(kv) {
      var platform = kv[0],
        platform_modules = kv[1];
      _.pairs(platform_modules).forEach(function(kv) {
        var id = kv[0],
          id_modules = kv[1];
        tasks.push(function() {
          install(_.defaults({
            id: id,
            platform: platform.replace("iphone", "ios")
          }, o));
        });
      });
    });
  }
  if (tasks.length > 0) {
    async.parallel(tasks);
  } else {
    logger.warn('no modules found to ' + (o.update ? 'update' : 'install'));
  }
}

function info(id, options) {

  config.init(true, function() {
    component.lookup(id, function(err, info) {
      if (err) {
        if (options.output === "json") {
          console.log(JSON.stringify({
            error: err
          }));
        } else {
          logger.error(err);
        }
        return;
      }
      if (options.output === "json") {
        console.log(JSON.stringify(info, null, '  '));
      } else {
        utils.prettyJSON(info);
        console.log('');
      }
    }, {
      silent: options.output === "json",
      action: 'info'
    });
  });
}

function demo(o) {
  var project_path = path.join(process.cwd(), o.id);

  if (config.context === 'project') {
    logger.error('will not create a project within a project: ' + project_path);
    return;
  }

  if (fs.existsSync(project_path)) {
    logger.error('cannot create already existing: ' + project_path);
    return;
  }

  component.lookup(o.id, function(err, cmp) {

    if (err) {
      logger.error(err);
      return;
    }

    if (cmp.type !== 'module') {
      logger.error('demo only works with modules.');
      return;
    }

    // filter all dists
    var dists = component.filterDists(cmp, o);

    // nothing to install
    if (dists.length === 0) {
      var prefix = utils.prefix(o.id, o.version);
      return;
    }

    console.log('');
    console.log('--- CREATING PROJECT ---');
    console.log('');

    // create project
    exec('ti', ['create', '-t', 'app', '-u', 'http://gitt.io', '-p', cmp.platforms.join(','), '-n', cmp.id, '--id', cmp.id, '-d', process.cwd()], null, function() {

      console.log('--- INSTALLING MODULE ---');
      console.log('');

      // install module
      exec('gittio', ['install', cmp.id + (o.version ? '@' + o.version : '') + (o.platform ? ':' + o.platform : '')], {
        cwd: project_path
      }, function() {

        console.log('');
        console.log('--- PREPARING EXAMPLES ---');
        console.log('');

        var build = null;

        // if the user defined the platform(s) we only want those
        if (undefined !== o.platform) {
          cmp.platforms = _.intersection(cmp.platforms, o.platform.split(','));

          if (cmp.platforms.length === 0) {
            console.error('The module has none of the requested platforms.');
            return;
          }
        }

        // for each platform
        _.some(cmp.platforms, function(platform) {

          if (platform === 'ios') {
            platform = 'iphone';
          }

          var module_path = path.join(project_path, 'modules', platform, cmp.id);
          var version = fs.readdirSync(module_path)[0];
          var example_path = path.join(module_path, version, 'example');

          // no example
          if (!fs.existsSync(path.join(example_path, 'app.js'))) {
            logger.warn('No example for ' + platform);
            return;
          }

          logger.info('Copied example for ' + platform);

          // copy example
          fs.copySync(example_path, path.join(project_path, 'Resources', platform));

          build = build || platform;

          // break the loop, we only need one example
          return true;
        });

        // no examples
        if (!build) {
          logger.error('No examples found.');
          return;
        }

        console.log('');
        console.log('--- BUILDING PROJECT ---');
        console.log('');

        // build first platform
        exec('ti', ['build', '-p', build], {
          cwd: project_path
        });
      });
    });
  }, {
    action: 'demo'
  });
}

exports.install = install;
exports.uninstall = uninstall;
exports.info = info;
exports.demo = demo;<commit_msg>Store the actual version, not the range<commit_after>var path = require('path'),
  config = require('./config'),
  alloy = require('./alloy'),
  component = require('./component'),
  dist = require('./dist'),
  tiapp = require('./tiapp'),
  exec = require('./exec'),
  rimraf = require('rimraf'),
  logger = require('./logger'),
  _ = require('underscore'),
  fs = require('fs-extended'),
  path = require('path'),
  semver = require('semver'),
  utils = require('./utils'),
  async = require('async');

function uninstall(o) {

  if (o.version === '*') {
    delete o.version;
  }

  if (!_uninstallWidget(o)) {
    _uninstallModule(o);
  }
}

function _uninstallWidget(o) {
  if (config.context === 'global' || !fs.existsSync(config.widgets_path)) {
    return false;
  }
  var trgPath = path.join(config.widgets_path, o.id);
  var files = fs.readdirSync(config.widgets_path);
  var found = _.find(files, function(f) {
    return f === o.id;
  });
  var installed = found && (o.version === undefined || require(path.join(trgPath, 'widget.json')).version === o.version);
  var prefix = utils.prefix(o.id, o.version);
  if (installed) {
    rimraf.sync(trgPath);
    alloy.dropDependency(o.id, o.version);

    logger.info(prefix + ' uninstalled');

    return true;
  } else {
    found = _.find(files, function(f) {
      return f.toLowerCase() === o.id.toLowerCase();
    });
    if (found) {
      logger.error("Did you mean " + found + "?");
      return true;
    }
  }

  return false;
}

function _uninstallModule(o) {
  var trgPath = o.global ? config.global_modules_path : path.join(config.modules_path);
  var platform = (o.platform ? o.platform.replace("ios", "iphone") : undefined);
  var uninstalled = false;

  if (config.context === "project") {
    tiapp.dropDependency(o.id, o.version, platform);
  }

  if (o.global || config.context !== "project") {
    _.pairs(config.available_modules.global).forEach(function(kv) {
      var platform = kv[0],
        platform_modules = kv[1];
      if (o.platform === undefined || o.platform == platform) {
        _.pairs(platform_modules).forEach(function(kv) {
          var id = kv[0],
            id_modules = kv[1];
          if (o.id === id) {
            _.pairs(id_modules).forEach(function(kv) {
              var version = kv[0],
                module = kv[1];
              if (o.version === undefined || o.version === version) {
                var modulePath = path.join(module.modulePath);
                if (fs.existsSync(modulePath)) {
                  rimraf.sync(path.join(module.modulePath));
                  uninstalled = true;
                }
              }
            });
          }
        });
      }
    });
  } else {
    config.current_modules.map(function(m) {
      if (m.name === o.id &&
        (o.version === undefined || o.version === m.version) &&
        (platform === undefined || platform === m.platform)) {
        tiapp.dropDependency(o.id, o.version, platform);
        var modulePath = path.join(trgPath, m.platform, m.name);
        if (fs.existsSync(modulePath)) {
          rimraf.sync(modulePath);
          uninstalled = true;
        }
      }
    });
  }

  var prefix = utils.prefix(o.id, o.version);

  if (uninstalled) {
    logger.info(prefix + ' uninstalled');
  } else {
    logger.warn(prefix + ' not installed');
  }
}

function install(o) {

  if (o.version === '*') {
    delete o.version;
  }

  if (o.url) {
    return _installUrl(o.url, o);

  } else if (o.file) {
    return _installFile(o.file, o);

  } else if (o.id) {
    return _installSingle(o);

  } else {
    if (config.context === "global") {
      if (o.update && o.type !== "widget") {
        return _installAllModules(o);
      } else {
        logger.error("This command must be executed from a project directory");
        return;
      }
    }
    if (o.type === 'widget') {
      return _installAllWidgets(o);
    } else if (o.type === 'module') {
      return _installAllModules(o);
    } else {
      return _installAll(o);
    }
  }
}

function _addDependency(cmp, dst, o) {
  if (cmp.type === 'module' && config.context === 'project') {
    tiapp.addDependency(cmp.id, dst.version, dst.platforms);
  } else if (cmp.type === 'widget') {
    alloy.addDependency(cmp.id, dst.version);
  }
}

function findDown(dir, file) {

  if (fs.existsSync(path.join(dir, file))) {
    return file;
  }

  var files = fs.listAllSync(dir, {
    recursive: true,
    filter: function(itemPath, stat) {
      return (stat.isFile() && path.basename(itemPath) === file);
    }
  });

  if (files.length === 1) {
    return files[0];
  }

  return null;
}

function _installDir(dir, o) {

  var cmp = {};
  var dst = {};

  var widgetJson_path = findDown(dir, 'widget.json');

  if (widgetJson_path) {
    var widgetJson = require(path.join(dir, widgetJson_path));

    cmp.id = widgetJson.id;
    cmp.type = 'widget';

    dst.version = widgetJson.version;
    dst.srcPath = path.dirname(widgetJson_path);
    dst.trgPath = path.join(config.widgets_path, cmp.id);

  } else {

    var manifest_path = findDown(dir, 'manifest');

    if (!manifest_path) {
      logger.error('Cannot find a module manifest');
      return;
    }

    var manifest = fs.readFileSync(path.join(dir, manifest_path)).toString();
    var match;

    if (match = manifest.match(/^version: ?([^\n]+)$/m)) {
      dst.version = match[1];
    }

    if (match = manifest.match(/^moduleid: ?([^\n]+)$/m)) {
      cmp.id = match[1];

    } else {
      logger.error('Cannot find module id in the manifest');
      return;
    }

    if (match = manifest.match(/^platform(?:s)?: ?([^\n]+)$/m)) {
      dst.platforms = match[1].split(',');

    } else {
      logger.error('Cannot find target platforms in the manifest');
      return;
    }

    cmp.type = 'module';

    dst.srcPath = 'modules';
    dst.trgPath = o.global ? config.global_modules_path : config.modules_path;
  }

  var prefix = utils.prefix(cmp.id, dst.version, dst.platforms);

  // copy from tmpPath
  fs.copyDir(path.join(dir, dst.srcPath), dst.trgPath, function(err) {

    if (err) {
      logger.error(err);
      return;
    }

    // add dependency
    _addDependency(cmp, dst, o);

    // remove tmpPath
    rimraf.sync(dir);

    logger.info(prefix + ' installed');
  });
}

function _installUrl(url, o) {

  dist.download(url, function(err, dir) {

    if (err) {
      logger.error(err);
      return;
    }

    _installDir(dir, o);

  });
}

function _installFile(file, o) {

  dist.extract(file, function(err, dir) {

    if (err) {
      logger.error(err);
      return;
    }

    _installDir(dir, o);

  });
}

function _installSingle(o) {

  component.lookup(o.id, function(err, cmp) {

    if (err) {
      logger.error(err);
      return;
    }

    if (cmp.type === 'widget' && !config.isAlloy) {
      logger.error('Widgets must be installed within an Alloy project directory.');
      return;
    }

    // filter all dists
    var dists = component.filterDists(cmp, o);

    // nothing to install
    if (dists.length === 0) {
      return;
    }

    // for all dists
    _.each(dists, function(dst) {
      var prefix = utils.prefix(cmp.id, dst.version, dst.platforms),
        installed = dist.isInstalled(cmp, dst, o);

      // already installed
      if (installed && !o.force) {
        logger.warn(prefix + ' already installed');

        // add dependency
        _addDependency(cmp, dst, o);

      } else {

        // download
        logger.info(prefix + ' downloading...');

        dist.download(dst.dist, function(err, tmpPath) {

          if (err) {
            logger.error(err);
            return;
          }

          logger.info(prefix + ' installing...');

          // copy from tmpPath
          fs.copyDirSync(path.join(tmpPath, dst.srcPath), dst.trgPath);

          if (err) {
            logger.error(err);
            return;
          }

          // add dependency
          _addDependency(cmp, dst, o);

          // recursive widget dependencies
          if (cmp.type === 'widget') {
            var widget = require(path.join(dst.trgPath, 'widget.json'));

            // include our self-declared 'modules' dependencies
            var dependencies = _.extend({}, widget.dependencies || {}, widget.modules || {});

            if (_.size(dependencies) > 0) {
              var tasks = _.pairs(dependencies).map(function(kv) {
                var id = kv[0],
                  version = kv[1];

                return function() {
                  install(_.defaults({
                    id: id,
                    version: version
                  }, o));
                };

              });

              // install dependencies
              if (tasks.length > 0) {
                async.parallel(tasks);
              }
            }
          }

          // remove tmpPath
          rimraf.sync(tmpPath);

          logger.info(prefix + ' installed');
        });
      }
    });
  }, {
    action: o.update ? 'update' : 'install'
  });
}

function _installAll(o) {
  async.parallel([
    _.bind(_installAllWidgets, undefined, o),
    _.bind(_installAllModules, undefined, o)
  ]);
}

function _installAllWidgets(o) {

  if (config.isAlloy) {
    var data = config.alloy_config;

    if (data.dependencies && _.size(data.dependencies) > 0) {
      var tasks = [];

      _.each(data.dependencies, function(version, widget) {
        tasks.push(function() {
          install(_.extend({
            id: widget,
            version: o.update ? undefined : version
          }, o));
        });
      });

      async.parallel(tasks);

    } else {
      logger.warn('no widgets found to ' + (o.update ? 'update' : 'install'));
    }
  }
}

function _installAllModules(o) {
  var tasks;
  if (config.context === "project") {
    tasks = config.current_modules.map(function(m) {
      return function() {
        install(_.defaults({
          id: m.name,
          version: o.update ? undefined : m.version,
          platform: m.platform.replace("iphone", "ios")
        }, o));
      };
    });
  } else {
    tasks = [];
    _.pairs(config.available_modules.global).forEach(function(kv) {
      var platform = kv[0],
        platform_modules = kv[1];
      _.pairs(platform_modules).forEach(function(kv) {
        var id = kv[0],
          id_modules = kv[1];
        tasks.push(function() {
          install(_.defaults({
            id: id,
            platform: platform.replace("iphone", "ios")
          }, o));
        });
      });
    });
  }
  if (tasks.length > 0) {
    async.parallel(tasks);
  } else {
    logger.warn('no modules found to ' + (o.update ? 'update' : 'install'));
  }
}

function info(id, options) {

  config.init(true, function() {
    component.lookup(id, function(err, info) {
      if (err) {
        if (options.output === "json") {
          console.log(JSON.stringify({
            error: err
          }));
        } else {
          logger.error(err);
        }
        return;
      }
      if (options.output === "json") {
        console.log(JSON.stringify(info, null, '  '));
      } else {
        utils.prettyJSON(info);
        console.log('');
      }
    }, {
      silent: options.output === "json",
      action: 'info'
    });
  });
}

function demo(o) {
  var project_path = path.join(process.cwd(), o.id);

  if (config.context === 'project') {
    logger.error('will not create a project within a project: ' + project_path);
    return;
  }

  if (fs.existsSync(project_path)) {
    logger.error('cannot create already existing: ' + project_path);
    return;
  }

  component.lookup(o.id, function(err, cmp) {

    if (err) {
      logger.error(err);
      return;
    }

    if (cmp.type !== 'module') {
      logger.error('demo only works with modules.');
      return;
    }

    // filter all dists
    var dists = component.filterDists(cmp, o);

    // nothing to install
    if (dists.length === 0) {
      var prefix = utils.prefix(o.id, o.version);
      return;
    }

    console.log('');
    console.log('--- CREATING PROJECT ---');
    console.log('');

    // create project
    exec('ti', ['create', '-t', 'app', '-u', 'http://gitt.io', '-p', cmp.platforms.join(','), '-n', cmp.id, '--id', cmp.id, '-d', process.cwd()], null, function() {

      console.log('--- INSTALLING MODULE ---');
      console.log('');

      // install module
      exec('gittio', ['install', cmp.id + (o.version ? '@' + o.version : '') + (o.platform ? ':' + o.platform : '')], {
        cwd: project_path
      }, function() {

        console.log('');
        console.log('--- PREPARING EXAMPLES ---');
        console.log('');

        var build = null;

        // if the user defined the platform(s) we only want those
        if (undefined !== o.platform) {
          cmp.platforms = _.intersection(cmp.platforms, o.platform.split(','));

          if (cmp.platforms.length === 0) {
            console.error('The module has none of the requested platforms.');
            return;
          }
        }

        // for each platform
        _.some(cmp.platforms, function(platform) {

          if (platform === 'ios') {
            platform = 'iphone';
          }

          var module_path = path.join(project_path, 'modules', platform, cmp.id);
          var version = fs.readdirSync(module_path)[0];
          var example_path = path.join(module_path, version, 'example');

          // no example
          if (!fs.existsSync(path.join(example_path, 'app.js'))) {
            logger.warn('No example for ' + platform);
            return;
          }

          logger.info('Copied example for ' + platform);

          // copy example
          fs.copySync(example_path, path.join(project_path, 'Resources', platform));

          build = build || platform;

          // break the loop, we only need one example
          return true;
        });

        // no examples
        if (!build) {
          logger.error('No examples found.');
          return;
        }

        console.log('');
        console.log('--- BUILDING PROJECT ---');
        console.log('');

        // build first platform
        exec('ti', ['build', '-p', build], {
          cwd: project_path
        });
      });
    });
  }, {
    action: 'demo'
  });
}

exports.install = install;
exports.uninstall = uninstall;
exports.info = info;
exports.demo = demo;
<|endoftext|>


<commit_before>var exec = require('child_process').exec,
    util = require('./index'),
    spawn = require('child_process').spawn,
    fs = require('fs'),
    path = require('path'),
    Stack = require('./stack').Stack,
    cover = require('../lib/coverage'),
    wrapper = path.join(__dirname, './wrapper/wrapper.js');

exports.init = function(options, callback) {
    options = options || {};
    options.paths = options.paths || [];
    exports.check(function(version) {
        if (!version) {
            console.error('Please install the phantomjs binary in your path!');
            util.exit(1);
        }

        if (!options.silent && !options.quiet) {
            util.log('Starting Grover on ' + options.paths.length  + ' files with PhantomJS@' + version);
            util.log('  Running ' + options.concurrent + ' concurrent tests at a time.');

            if (options.timeout) {
                util.log('  Using a ' + options.timeout + ' second timeout per test.');
            }
        }
        if (options.server) {
            require('../lib/server').start(options);
        }
        if (options.exitOnFail) {
            util.log('--will exit on first test error');
        }

        callback(version);
    });
};

exports.check = function(callback) {
    exec('phantomjs --version', function(stdin, stdout) {
        var version = stdout.replace('\n', '');
        callback(version);
    });
};

exports.test = function(options, file, callback) {
    var args = [
        wrapper,
        file
    ],
    stdout = '', child;

    if (!util.existsSync(file) && !file.match(/^https?:\/\//) && !options.server) {
        if (util.canPrint(options)) {
            util.error(':( Can not find file: ' + file);
        }
        util.exit(1);
    }

    if (options.timeout) {
        args.push(options.timeout);
    }
    child = spawn('phantomjs', args);
    child.stdout.on('data', function(data) {
        stdout += data;
    });
    child.on('exit', function() {
        try {
            var results = JSON.parse(stdout);
            if (util.canPrint(options, results)) {
                util.status(results);
            }
            if (options.exitOnFail && results.failed) {
                util.exit(1);
            }
            callback(null, results);
        } catch (e) {
            util.error('Failed to parse response for ' + args[1] + ', readding to queue');
            callback(args[1]);
        }
    });
};

exports.dispatch = function(options, callback) {
    var stack = new Stack(),
        testResults = [],
        noop = function() {},
        run = function(cb) {
            var file = options.paths.shift();
            if (file) {
                exports.test(options, file, function(err, json) {
                    if (err) {
                        options.paths.unshift(file);
                    } else {
                        testResults.push(json);
                    }
                    run(stack.add(noop));
                    cb();
                });
            } else {
                cb();
            }
        };

    for (i = 1; i < options.concurrent; i++) {
        run(stack.add(noop));
    }
    stack.done(function() {
        callback(null, testResults);
    });
};

exports.process = function(callback) {
    var options = require('./options').parse(process.argv.slice(2)),
        done = false;
    exports.init(options, function() {
        var runTests = function () {
            if (done) {
                return; //Don't execute more tests
            }
            options.START = (new Date()).getTime();
            exports.dispatch(options, function(err, results) {
                done = true;
                exports.done(options, results, callback);
            });
        };

        if (options.run){
            runTests();
        } else {
            util.log('not running tests, just serving them.');
            process.on('SIGCONT', function() {
                util.log('Received parent message, continuing test execution');
                runTests();
            });
            process.on('message', function (msg) {
                if (msg['continue']) {
                    util.log('Received parent message, continuing test execution');
                    //Reset start timer because we were paused
                    runTests();
                }
            });
        }

    });
};

exports.done = function(options, testResults, callback) {
        var res = {
            name: 'Total',
            passed: 0,
            failed: 0,
            ignored: 0,
            total: 0,
            duration: 0
        }, proc, output, END;

        if (options.server) {
            options.httpd.close();
        }
        if (options.outfile && options.outtype) {
            proc = require(path.join(__dirname, '../lib/process'));
            output = proc(testResults, options.outtype);

            if (!options.silent && !options.quiet) {
                util.log('Writing files in ' + options.outtype + ' format to: ' + options.outfile);
            }
            fs.writeFileSync(options.outfile, output, 'utf8');
        }

        cover.options(options);

        testResults.forEach(function(json) {
            res.passed += json.passed;
            res.failed += json.failed;
            res.total += json.total;
            res.ignored += json.ignored;
            res.duration += json.duration;
            if (json.coverage) {
                cover.set(json.coverage);
            }
        });

        END = (new Date()).getTime();
        if (!options.silent && !options.quiet && !options.coverage) {
            console.log('----------------------------------------------------------------');
            util.status(res, options.START, END);
        }
        if (res.failed) {
            util.exit(1);
        }
        if (options.coverage) {
            cover.report();
            console.log('----------------------------------------------------------------');
            util.status(res, options.START, END);
            cover.save(options);
        }
        if (process.send) {
            process.send({ done: true });
            util.exit(0);
        }

        if (callback) {
            callback(null, testResults);
        }

};
<commit_msg>Some testing tweaks and bug fixes<commit_after>var exec = require('child_process').exec,
    util = require('./index'),
    spawn = require('child_process').spawn,
    fs = require('fs'),
    path = require('path'),
    Stack = require('./stack').Stack,
    cover = require('../lib/coverage'),
    wrapper = path.join(__dirname, './wrapper/wrapper.js');

exports.init = function(options, callback) {
    options = options || {};
    options.paths = options.paths || [];
    exports.check(function(version) {
        if (!version) {
            console.error('Please install the phantomjs binary in your path!');
            util.exit(1);
        }

        if (!options.silent && !options.quiet) {
            util.log('Starting Grover on ' + options.paths.length  + ' files with PhantomJS@' + version);
            util.log('  Running ' + options.concurrent + ' concurrent tests at a time.');

            if (options.timeout) {
                util.log('  Using a ' + options.timeout + ' second timeout per test.');
            }
        }
        if (options.server) {
            require('../lib/server').start(options);
        }
        if (options.exitOnFail) {
            util.log('--will exit on first test error');
        }

        callback(version);
    });
};

exports.check = function(callback) {
    exec('phantomjs --version', function(stdin, stdout) {
        var version = stdout.replace('\n', '');
        callback(version);
    });
};

exports.test = function(options, file, callback) {
    var args = [
        wrapper,
        file
    ],
    stdout = '', child;

    if (!util.existsSync(file) && !file.match(/^https?:\/\//) && !options.server) {
        if (util.canPrint(options)) {
            util.error(':( Can not find file: ' + file);
        }
        util.exit(1);
    }

    if (options.timeout) {
        args.push(options.timeout);
    }
    child = spawn('phantomjs', args);
    child.stdout.on('data', function(data) {
        stdout += data;
    });
    child.on('exit', function() {
        var err = null,
            results;
        try {
            results = JSON.parse(stdout);
            if (util.canPrint(options, results)) {
                util.status(results);
            }
            if (options.exitOnFail && results.failed) {
                util.exit(1);
            }
        } catch (e) {
            util.error('Failed to parse response for ' + args[1] + ', readding to queue');
            err = args[1];
        }
        callback(err, results);
    });
};

exports.dispatch = function(options, callback) {
    var stack = new Stack(),
        testResults = [],
        noop = function() {},
        run = function(cb) {
            var file = options.paths.shift();
            if (file) {
                exports.test(options, file, function(err, json) {
                    if (err) {
                        options.paths.unshift(file);
                    } else {
                        testResults.push(json);
                    }
                    run(stack.add(noop));
                    cb();
                });
            } else {
                cb();
            }
        };

    for (i = 1; i < options.concurrent; i++) {
        run(stack.add(noop));
    }
    stack.done(function() {
        callback(null, testResults);
    });
};

exports.process = function(args, callback) {
    if (typeof args === 'function') {
        callback = args;
        args = null;
    }
    args = args || process.argv.slice(2);
    var options = require('./options').parse(args),
        done = false;

    exports.init(options, function() {
        cover.init();
        var runTests = function () {
            if (done) {
                return; //Don't execute more tests
            }
            options.START = (new Date()).getTime();
            exports.dispatch(options, function(err, results) {
                done = true;
                exports.done(options, results, callback);
            });
        };

        if (options.run){
            runTests();
        } else {
            util.log('not running tests, just serving them.');
            process.on('SIGCONT', function() {
                util.log('Received parent message, continuing test execution');
                runTests();
            });
            process.on('message', function (msg) {
                if (msg['continue']) {
                    util.log('Received parent message, continuing test execution');
                    //Reset start timer because we were paused
                    runTests();
                }
            });
        }

    });
};

exports.done = function(options, testResults, callback) {
        var res = {
            name: 'Total',
            passed: 0,
            failed: 0,
            ignored: 0,
            total: 0,
            duration: 0
        }, proc, output, END;

        if (options.server) {
            options.httpd.close();
        }
        if (options.outfile && options.outtype) {
            proc = require(path.join(__dirname, '../lib/process'));
            output = proc(testResults, options.outtype);

            if (!options.silent && !options.quiet) {
                util.log('Writing files in ' + options.outtype + ' format to: ' + options.outfile);
            }
            fs.writeFileSync(options.outfile, output, 'utf8');
        }

        cover.options(options);

        testResults.forEach(function(json) {
            res.passed += json.passed;
            res.failed += json.failed;
            res.total += json.total;
            res.ignored += json.ignored;
            res.duration += json.duration;
            if (json.coverage) {
                cover.set(json.coverage);
            }
        });

        END = (new Date()).getTime();
        if (!options.silent && !options.quiet && !options.coverage) {
            console.log('----------------------------------------------------------------');
            util.status(res, options.START, END);
        }
        if (res.failed) {
            util.exit(1);
        }
        if (options.coverage) {
            cover.report();
            console.log('----------------------------------------------------------------');
            util.status(res, options.START, END);
            cover.save(options);
        }
        if (process.send) {
            process.send({ done: true });
            util.exit(0);
        }

        if (callback) {
            callback(null, testResults);
        }

};
<|endoftext|>


<commit_before>/*
  This code was derived from lodash.js (the _.escape function)
  https://github.com/lodash/lodash
 */
const reUnescapedHtml = /[&<>"]/g;
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
const htmlEscapes = {
  '&': '&',
  '<': '<',
  '>': '>',
  '"': '"'
};

const escape = string => {
  const result = String(string);
  return (result && reHasUnescapedHtml.test(result))
    ? result.replace(reUnescapedHtml, chr => htmlEscapes[chr])
    : result;
};
/* end of derivation from lodash */

const isCongruent = (a, b) => (
  (typeof a === 'string' && typeof b === 'string')
  || (a && a[0].$name === b.$name)
);

const pushTogether = (a, b) => (typeof a === 'string' ? a + b : a.concat(b));

const condenseArray = items => items.reduce(
  (result, element) => {
    const lastPosition = result.length - 1;
    const last = result[lastPosition];
    if (isCongruent(last, element)) result[lastPosition] = pushTogether(last, element);
    else result.push(typeof element === 'string' ? element : [ element ]);
    return result;
  }, []
);

const disassembleNode = (node, dropName, unwrap) => {
  let $attrs = null;
  const stripped = {};
  Object.keys(node).forEach(key => {
    const val = isSomething(node[key]) ? node[key] : null;
    if (!val) return;
    switch (key) {
      case '$name':
        if (!dropName && val) stripped.$name = val;
        break;

      case '$attrs':
        $attrs = val;
        break;

      case '$markup':
        stripped.$markup = simplifyAll(val);
        break;

      default:
        if (val) stripped[key] = unwrap(val);
    }
  });
  return { stripped, $attrs };
};

const unwrapSingleArrays = x => (Array.isArray(x) && x.length === 1 ? x[0] : x);

const tryMergingAttrs = ($attrs, stripped) => {
  if (!isSomething(stripped)) return $attrs;
  if (!$attrs) return stripped;
  const keys = Object.keys(stripped);
  if (keys.length === 1 && stripped.$name) return Object.assign(stripped, $attrs);
  return Object.assign(stripped, { $attrs });
};

const tryGuttingNode = node => {
  const keys = Object.keys(node);
  const [ firstKey ] = keys;
  if (
    keys.length === 1
    && firstKey !== '$name'
    && firstKey !== 'id'
  ) return node[keys[0]];
  return node;
};

const simplifyNode = (node, dropName, keepArrays) => {
  const unwrap = keepArrays ? x => x : unwrapSingleArrays;
  const unwrapped = unwrap(node);
  if (!isSomething(unwrapped)) return null;
  if (
    typeof unwrapped !== 'object'
    || Array.isArray(unwrapped)
  ) return unwrapped;
  const { $attrs, stripped } = disassembleNode(unwrapped, dropName, unwrap);
  const merged = tryMergingAttrs($attrs, stripped);
  return tryGuttingNode(merged);
};

const shouldObjectifyMarkup = items => {
  let currentTag;
  const foundTags = {};
  let shouldObjectify = true;

  items.every(item => {
    if (typeof item === 'string') {
      currentTag = '$text';
    } else {
      currentTag = item[0].$name;
    }

    if (foundTags[currentTag]) {
      shouldObjectify = false;
      return false;
    }
    foundTags[currentTag] = true;
    return true;
  });
  return shouldObjectify;
};

/**
 * Try to concatenate things into one array (arrays, strings, whatever).
 * Be smart about the inputs, so as to create a simple array.
 * @param  {any}   [a=[]]                         String, array, whatever
 * @param  {any}   [b=[]]                         String, array, whatever
 * @param  {boolean} [preserveSingleArrays=false] Whether to unwrap a result of length = 1
 * @return {Array|any}                            The mooshing of the inputs
 */
const moosh = (a = [], b = [], preserveSingleArrays = false) => {
  const arrayA = Array.isArray(a) ? a : [ a ];
  const arrayB = Array.isArray(b) ? b : [ b ];
  const mooshed = arrayA.concat(arrayB);
  return ((mooshed.length === 1 && !preserveSingleArrays) ? mooshed[0] : mooshed);
};

const simplifyAll = (input, dropName) => {
  const output = [];
  if (input !== null && typeof input === 'object' && input.constructor === Array) {
    input.forEach(item => {
      output.push(simplifyNode(item, dropName));
    });
    return output;
  }
  return simplifyNode(input, dropName);
};

const objectifyMarkup = (node, keepArrays) => {
  let key;
  const output = {};

  Object.keys(node).forEach(nodeKey => {
    if (nodeKey !== '$markup') {
      output[nodeKey] = node[nodeKey];
    }
  });

  if (node.$markup) {
    node.$markup.forEach(item => {
      if (typeof item === 'string') {
        output.$text = moosh(output.$text, item, keepArrays);
      } else if (typeof item === 'object') {
        if (item.constructor === Array) {
          key = item[0].$name;
        } else {
          key = item.$name;
        }
        output[key] = moosh(output[key], simplifyAll(item, true), keepArrays);
      }
    });
  }
  return output;
};

const isSomething = value => (
  value != null
  && (value.length == null || value.length !== 0)
  && (typeof value !== 'object' || Object.keys(value).length !== 0)
);

module.exports = {
  condenseArray,
  escape,
  isSomething,
  moosh,
  objectifyMarkup,
  shouldObjectifyMarkup,
  simplifyNode
};
<commit_msg>a trimmed space only text will fail in tryGuttingNode<commit_after>/*
  This code was derived from lodash.js (the _.escape function)
  https://github.com/lodash/lodash
 */
const reUnescapedHtml = /[&<>"]/g;
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
const htmlEscapes = {
  '&': '&',
  '<': '<',
  '>': '>',
  '"': '"'
};

const escape = string => {
  const result = String(string);
  return (result && reHasUnescapedHtml.test(result))
    ? result.replace(reUnescapedHtml, chr => htmlEscapes[chr])
    : result;
};
/* end of derivation from lodash */

const isCongruent = (a, b) => (
  (typeof a === 'string' && typeof b === 'string')
  || (a && a[0].$name === b.$name)
);

const pushTogether = (a, b) => (typeof a === 'string' ? a + b : a.concat(b));

const condenseArray = items => items.reduce(
  (result, element) => {
    const lastPosition = result.length - 1;
    const last = result[lastPosition];
    if (isCongruent(last, element)) result[lastPosition] = pushTogether(last, element);
    else result.push(typeof element === 'string' ? element : [ element ]);
    return result;
  }, []
);

const disassembleNode = (node, dropName, unwrap) => {
  let $attrs = null;
  const stripped = {};
  Object.keys(node).forEach(key => {
    const val = isSomething(node[key]) ? node[key] : null;
    if (!val) return;
    switch (key) {
      case '$name':
        if (!dropName && val) stripped.$name = val;
        break;

      case '$attrs':
        $attrs = val;
        break;

      case '$markup':
        stripped.$markup = simplifyAll(val);
        break;

      default:
        if (val) stripped[key] = unwrap(val);
    }
  });
  return { stripped, $attrs };
};

const unwrapSingleArrays = x => (Array.isArray(x) && x.length === 1 ? x[0] : x);

const tryMergingAttrs = ($attrs, stripped) => {
  if (!isSomething(stripped)) return $attrs;
  if (!$attrs) return stripped;
  const keys = Object.keys(stripped);
  if (keys.length === 1 && stripped.$name) return Object.assign(stripped, $attrs);
  return Object.assign(stripped, { $attrs });
};

const tryGuttingNode = node => {
  if (!node) return;
  const keys = Object.keys(node);
  const [ firstKey ] = keys;
  if (
    keys.length === 1
    && firstKey !== '$name'
    && firstKey !== 'id'
  ) return node[keys[0]];
  return node;
};

const simplifyNode = (node, dropName, keepArrays) => {
  const unwrap = keepArrays ? x => x : unwrapSingleArrays;
  const unwrapped = unwrap(node);
  if (!isSomething(unwrapped)) return null;
  if (
    typeof unwrapped !== 'object'
    || Array.isArray(unwrapped)
  ) return unwrapped;
  const { $attrs, stripped } = disassembleNode(unwrapped, dropName, unwrap);
  const merged = tryMergingAttrs($attrs, stripped);
  return tryGuttingNode(merged);
};

const shouldObjectifyMarkup = items => {
  let currentTag;
  const foundTags = {};
  let shouldObjectify = true;

  items.every(item => {
    if (typeof item === 'string') {
      currentTag = '$text';
    } else {
      currentTag = item[0].$name;
    }

    if (foundTags[currentTag]) {
      shouldObjectify = false;
      return false;
    }
    foundTags[currentTag] = true;
    return true;
  });
  return shouldObjectify;
};

/**
 * Try to concatenate things into one array (arrays, strings, whatever).
 * Be smart about the inputs, so as to create a simple array.
 * @param  {any}   [a=[]]                         String, array, whatever
 * @param  {any}   [b=[]]                         String, array, whatever
 * @param  {boolean} [preserveSingleArrays=false] Whether to unwrap a result of length = 1
 * @return {Array|any}                            The mooshing of the inputs
 */
const moosh = (a = [], b = [], preserveSingleArrays = false) => {
  const arrayA = Array.isArray(a) ? a : [ a ];
  const arrayB = Array.isArray(b) ? b : [ b ];
  const mooshed = arrayA.concat(arrayB);
  return ((mooshed.length === 1 && !preserveSingleArrays) ? mooshed[0] : mooshed);
};

const simplifyAll = (input, dropName) => {
  const output = [];
  if (input !== null && typeof input === 'object' && input.constructor === Array) {
    input.forEach(item => {
      output.push(simplifyNode(item, dropName));
    });
    return output;
  }
  return simplifyNode(input, dropName);
};

const objectifyMarkup = (node, keepArrays) => {
  let key;
  const output = {};

  Object.keys(node).forEach(nodeKey => {
    if (nodeKey !== '$markup') {
      output[nodeKey] = node[nodeKey];
    }
  });

  if (node.$markup) {
    node.$markup.forEach(item => {
      if (typeof item === 'string') {
        output.$text = moosh(output.$text, item, keepArrays);
      } else if (typeof item === 'object') {
        if (item.constructor === Array) {
          key = item[0].$name;
        } else {
          key = item.$name;
        }
        output[key] = moosh(output[key], simplifyAll(item, true), keepArrays);
      }
    });
  }
  return output;
};

const isSomething = value => (
  value != null
  && (value.length == null || value.length !== 0)
  && (typeof value !== 'object' || Object.keys(value).length !== 0)
);

module.exports = {
  condenseArray,
  escape,
  isSomething,
  moosh,
  objectifyMarkup,
  shouldObjectifyMarkup,
  simplifyNode
};
<|endoftext|>


<commit_before>export default function(){
  var vm = this; //hard binded to chart;

  var Helper = {
    chart: {
      config : vm._config,
      width: vm._width,
      height: vm._height,
      fullSvg : function(){
        return vm._fullSvg;
      },
      svg: function(){
        return vm._svg;
      }
    },
    utils:{}
  }

  Helper.utils.generateScale = function(data, config){
    var scale = {};
    var domains;
    if(!config.range) {
      throw 'Range is not defined';
    }
    //Used in bars.js when we want to create a groupBy or stackBy bar chart
    if(config.groupBy && config.groupBy == 'parent'){
      //Axis of type band
      domains = data.map(function(d) { return d[config.column]; });
    }else if( config.stackBy && config.stackBy == 'parent'){
      domains = data[0].map(function(d) { return d.data[config.column]; });
    }else if(config.groupBy == 'children'){
      //GroupBy Columns
      domains = config.column;
    }else if(config.groupBy == 'data'){
      //Considering the highest value on all the columns for each groupBy column
      domains = [0, d3.max(data, function(d) { return d3.max(config.column, function(column) { return d[column]; }); })];
    }else if(config.stackBy == 'data'){
      //Using a d3.stack()
      domains = [0, d3.max(data, function(serie) { return d3.max(serie, function(d) { return d[1]; }) } )];
    }else if(config.groupBy == undefined && config.type == 'band'){
      //In case the axis is of type band and there is no groupby
      domains = data.map(function(d) { return d[config.column]; });
    }else if(config.type === 'linear'){
      //Axis of type numeric
      domains = d3.extent(data, function(d){ return +d[config.column]});
    }else{
      //Axis of type band
      domains = data.map(function(d) { return d[config.column]; });
    }

    if(config.minZero){
      domains = [0, d3.max(data, function(d){ return +d[config.column]})];
    }

    if(config.type){
      switch(config.type){
        case 'linear':
          scale = d3.scaleLinear()
            .rangeRound(config.range)
            .domain(domains);
        break;

        case 'time':
          scale = d3.scaleTime()
            .range(config.range)
            //.domain(domains);
        break;

        case 'ordinal':
          scale = d3.scaleBand()
            .rangeRound(config.range)
            .padding(0.1)
            .domain(domains);
        break;

        case 'band':
        scale = d3.scaleBand()
            .rangeRound(config.range)
            .domain(domains)
            .padding(0.1)
        break;

        case 'quantile':
          scale = d3.scaleBand()
            .rangeRound(config.range)
            .padding(0.1)
            .domain(data.map(function(d){ return d[config.column]}));
          if(!config.bins)
            config.bins = 10;
          scale = d3.scaleQuantile()
            .range(d3.range(config.bins))
        break;

        default:
          scale = d3.scaleLinear()
            .rangeRound(config.range)
            .domain(domains);
        break;
      }
    }else{
      scale = d3.scaleLinear()
            .rangeRound(config.range)
            .domain(domains);
    }

    return scale;
  }

  Helper.utils.format = function(d){
    if(d % 1 == 0){
      return d3.format(",.0f")(d);
    } else if(d < 1 && d > 0) {
      return d3.format(",.2f")(d);
    } else {
      return d3.format(",.1f")(d);
    }
  };

  return Helper
}
<commit_msg>Allow to personalize domains<commit_after>export default function () {
  var vm = this; //hard binded to chart;

  var Helper = {
    chart: {
      config: vm._config,
      width: vm._width,
      height: vm._height,
      fullSvg: function () {
        return vm._fullSvg;
      },
      svg: function () {
        return vm._svg;
      }
    },
    utils: {}
  }

  Helper.utils.generateScale = function (data, config) {
    var scale = {};
    var domains;
    if (!config.range) {
      throw 'Range is not defined';
    }
    //Used in bars.js when we want to create a groupBy or stackBy bar chart
    if (config.groupBy && config.groupBy == 'parent') {
      //Axis of type band
      domains = data.map(function (d) {
        return d[config.column];
      });
    } else if (config.stackBy && config.stackBy == 'parent') {
      domains = data[0].map(function (d) {
        return d.data[config.column];
      });
    } else if (config.groupBy == 'children') {
      //GroupBy Columns
      domains = config.column;
    } else if (config.groupBy == 'data') {
      //Considering the highest value on all the columns for each groupBy column
      domains = [0, d3.max(data, function (d) {
        return d3.max(config.column, function (column) {
          return d[column];
        });
      })];
    } else if (config.stackBy == 'data') {
      //Using a d3.stack()
      domains = [0, d3.max(data, function (serie) {
        return d3.max(serie, function (d) {
          return d[1];
        })
      })];
    } else if (config.groupBy == undefined && config.type == 'band') {
      //In case the axis is of type band and there is no groupby
      domains = data.map(function (d) {
        return d[config.column];
      });
    } else if (config.type === 'linear') {
      //Axis of type numeric
      domains = d3.extent(data, function (d) {
        return +d[config.column];
      });
    } else {
      //Axis of type band
      domains = data.map(function (d) {
        return d[config.column];
      });
    }

    if (config.minZero) {
      domains = [0, d3.max(data, function (d) {
        return +d[config.column];
      })];
    }
    if (config.domains && Array.isArray(config.domains)) {
      domains = config.domains;
    }

    if (config.type) {
      switch (config.type) {
        case 'linear':
          scale = d3.scaleLinear()
            .rangeRound(config.range)
            .domain(domains);
          break;

        case 'time':
          scale = d3.scaleTime()
            .range(config.range)
          //.domain(domains);
          break;

        case 'ordinal':
          scale = d3.scaleBand()
            .rangeRound(config.range)
            .padding(0.1)
            .domain(domains);
          break;

        case 'band':
          scale = d3.scaleBand()
            .rangeRound(config.range)
            .domain(domains)
            .padding(0.1)
          break;

        case 'quantile':
          scale = d3.scaleBand()
            .rangeRound(config.range)
            .padding(0.1)
            .domain(data.map(function (d) {
              return d[config.column]
            }));
          if (!config.bins)
            config.bins = 10;
          scale = d3.scaleQuantile()
            .range(d3.range(config.bins))
          break;

        default:
          scale = d3.scaleLinear()
            .rangeRound(config.range)
            .domain(domains);
          break;
      }
    } else {
      scale = d3.scaleLinear()
        .rangeRound(config.range)
        .domain(domains);
    }

    return scale;
  }

  Helper.utils.format = function (d) {
    if (d % 1 == 0) {
      return d3.format(",.0f")(d);
    } else if (d < 1 && d > 0) {
      return d3.format(",.2f")(d);
    } else {
      return d3.format(",.1f")(d);
    }
  };

  return Helper
}
<|endoftext|>