<commit_before>// @remove-file-on-eject
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
'use strict';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

const fs = require('fs-extra');
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const execSync = require('child_process').execSync;
const spawn = require('react-dev-utils/crossSpawn');
const { defaultBrowsers } = require('react-dev-utils/browsersHelper');
const os = require('os');
const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup');

function isInGitRepository() {
  try {
    execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
    return true;
  } catch (e) {
    return false;
  }
}

function isInMercurialRepository() {
  try {
    execSync('hg --cwd . root', { stdio: 'ignore' });
    return true;
  } catch (e) {
    return false;
  }
}

function tryGitInit() {
  try {
    execSync('git --version', { stdio: 'ignore' });
    if (isInGitRepository() || isInMercurialRepository()) {
      return false;
    }

    execSync('git init', { stdio: 'ignore' });
    return true;
  } catch (e) {
    console.warn('Git repo not initialized', e);
    return false;
  }
}

function tryGitCommit(appPath) {
  try {
    execSync('git add -A', { stdio: 'ignore' });
    execSync('git commit -m "Initialize project using Create React App"', {
      stdio: 'ignore',
    });
    return true;
  } catch (e) {
    // We couldn't commit in already initialized git repo,
    // maybe the commit author config is not set.
    // In the future, we might supply our own committer
    // like Ember CLI does, but for now, let's just
    // remove the Git files to avoid a half-done state.
    console.warn('Git commit not created', e);
    console.warn('Removing .git directory...');
    try {
      // unlinkSync() doesn't work on directories.
      fs.removeSync(path.join(appPath, '.git'));
    } catch (removeErr) {
      // Ignore.
    }
    return false;
  }
}

module.exports = function(
  appPath,
  appName,
  verbose,
  originalDirectory,
  templateName
) {
  const appPackage = require(path.join(appPath, 'package.json'));
  const useYarn = fs.existsSync(path.join(appPath, 'yarn.lock'));

  if (!templateName) {
    console.log('');
    console.error(
      `A template was not provided. This is likely because you're using an outdated version of ${chalk.cyan(
        'create-react-app'
      )}.`
    );
    console.error(
      `Please note that global installs of ${chalk.cyan(
        'create-react-app'
      )} are no longer supported.`
    );
    return;
  }

  const templatePath = path.join(
    require.resolve(templateName, { paths: [appPath] }),
    '..'
  );

  let templateJsonPath;
  if (templateName) {
    templateJsonPath = path.join(templatePath, 'template.json');
  } else {
    // TODO: Remove support for this in v4.
    templateJsonPath = path.join(appPath, '.template.dependencies.json');
  }

  let templateJson = {};
  if (fs.existsSync(templateJsonPath)) {
    templateJson = require(templateJsonPath);
  }

  const templatePackage = templateJson.package || {};

  // Keys to ignore in templatePackage
  const templatePackageBlacklist = [
    'name',
    'version',
    'description',
    'keywords',
    'bugs',
    'license',
    'author',
    'contributors',
    'files',
    'main',
    'browser',
    'bin',
    'man',
    'directories',
    'repository',
    'devDependencies',
    'peerDependencies',
    'bundledDependencies',
    'optionalDependencies',
    'engineStrict',
    'os',
    'cpu',
    'preferGlobal',
    'private',
    'publishConfig',
  ];

  // Keys from templatePackage that will be merged with appPackage
  const templatePackageToMerge = ['dependencies', 'scripts'];

  // Keys from templatePackage that will be added to appPackage,
  // replacing any existing entries.
  const templatePackageToReplace = Object.keys(templatePackage).filter(key => {
    return (
      !templatePackageBlacklist.includes(key) &&
      !templatePackageToMerge.includes(key)
    );
  });

  // Copy over some of the devDependencies
  appPackage.dependencies = appPackage.dependencies || {};

  // Setup the script rules
  // TODO: deprecate 'scripts' key directly on templateJson
  const templateScripts = templatePackage.scripts || templateJson.scripts || {};
  appPackage.scripts = Object.assign(
    {
      start: 'react-scripts start',
      build: 'react-scripts build',
      test: 'react-scripts test',
      eject: 'react-scripts eject',
    },
    templateScripts
  );

  // Update scripts for Yarn users
  if (useYarn) {
    appPackage.scripts = Object.entries(appPackage.scripts).reduce(
      (acc, [key, value]) => ({
        ...acc,
        [key]: value.replace(/(npm run |npm )/, 'yarn '),
      }),
      {}
    );
  }

  // Setup the eslint config
  appPackage.eslintConfig = {
    extends: 'react-app',
  };

  // Setup the browsers list
  appPackage.browserslist = defaultBrowsers;

  // Add templatePackage keys/values to appPackage, replacing existing entries
  templatePackageToReplace.forEach(key => {
    appPackage[key] = templatePackage[key];
  });

  fs.writeFileSync(
    path.join(appPath, 'package.json'),
    JSON.stringify(appPackage, null, 2) + os.EOL
  );

  const readmeExists = fs.existsSync(path.join(appPath, 'README.md'));
  if (readmeExists) {
    fs.renameSync(
      path.join(appPath, 'README.md'),
      path.join(appPath, 'README.old.md')
    );
  }

  // Copy the files for the user
  const templateDir = path.join(templatePath, 'template');
  if (fs.existsSync(templateDir)) {
    fs.copySync(templateDir, appPath);
  } else {
    console.error(
      `Could not locate supplied template: ${chalk.green(templateDir)}`
    );
    return;
  }

  // modifies README.md commands based on user used package manager.
  if (useYarn) {
    try {
      const readme = fs.readFileSync(path.join(appPath, 'README.md'), 'utf8');
      fs.writeFileSync(
        path.join(appPath, 'README.md'),
        readme.replace(/(npm run |npm )/g, 'yarn '),
        'utf8'
      );
    } catch (err) {
      // Silencing the error. As it fall backs to using default npm commands.
    }
  }

  const gitignoreExists = fs.existsSync(path.join(appPath, '.gitignore'));
  if (gitignoreExists) {
    // Append if there's already a `.gitignore` file there
    const data = fs.readFileSync(path.join(appPath, 'gitignore'));
    fs.appendFileSync(path.join(appPath, '.gitignore'), data);
    fs.unlinkSync(path.join(appPath, 'gitignore'));
  } else {
    // Rename gitignore after the fact to prevent npm from renaming it to .npmignore
    // See: https://github.com/npm/npm/issues/1862
    fs.moveSync(
      path.join(appPath, 'gitignore'),
      path.join(appPath, '.gitignore'),
      []
    );
  }

  // Initialize git repo
  let initializedGit = false;

  if (tryGitInit()) {
    initializedGit = true;
    console.log();
    console.log('Initialized a git repository.');
  }

  let command;
  let remove;
  let args;

  if (useYarn) {
    command = 'yarnpkg';
    remove = 'remove';
    args = ['add'];
  } else {
    command = 'npm';
    remove = 'uninstall';
    args = ['install', '--save', verbose && '--verbose'].filter(e => e);
  }

  // Install additional template dependencies, if present
  // TODO: deprecate 'dependencies' key directly on templateJson
  const templateDependencies =
    templatePackage.dependencies || templateJson.dependencies;
  if (templateDependencies) {
    args = args.concat(
      Object.keys(templateDependencies).map(key => {
        return `${key}@${templateDependencies[key]}`;
      })
    );
  }

  // Install react and react-dom for backward compatibility with old CRA cli
  // which doesn't install react and react-dom along with react-scripts
  if (!isReactInstalled(appPackage)) {
    args = args.concat(['react', 'react-dom']);
  }

  // Install template dependencies, and react and react-dom if missing.
  if ((!isReactInstalled(appPackage) || templateName) && args.length > 1) {
    console.log();
    console.log(`Installing template dependencies using ${command}...`);

    const proc = spawn.sync(command, args, { stdio: 'inherit' });
    if (proc.status !== 0) {
      console.error(`\`${command} ${args.join(' ')}\` failed`);
      return;
    }
  }

  if (args.find(arg => arg.includes('typescript'))) {
    console.log();
    verifyTypeScriptSetup();
  }

  // Remove template
  console.log(`Removing template package using ${command}...`);
  console.log();

  const proc = spawn.sync(command, [remove, templateName], {
    stdio: 'inherit',
  });
  if (proc.status !== 0) {
    console.error(`\`${command} ${args.join(' ')}\` failed`);
    return;
  }

  // Create git commit if git repo was initialized
  if (initializedGit && tryGitCommit(appPath)) {
    console.log();
    console.log('Created git commit.');
  }

  // Display the most elegant way to cd.
  // This needs to handle an undefined originalDirectory for
  // backward compatibility with old global-cli's.
  let cdpath;
  if (originalDirectory && path.join(originalDirectory, appName) === appPath) {
    cdpath = appName;
  } else {
    cdpath = appPath;
  }

  // Change displayed command to yarn instead of yarnpkg
  const displayedCommand = useYarn ? 'yarn' : 'npm';

  console.log();
  console.log(`Success! Created ${appName} at ${appPath}`);
  console.log('Inside that directory, you can run several commands:');
  console.log();
  console.log(chalk.cyan(`  ${displayedCommand} start`));
  console.log('    Starts the development server.');
  console.log();
  console.log(
    chalk.cyan(`  ${displayedCommand} ${useYarn ? '' : 'run '}build`)
  );
  console.log('    Bundles the app into static files for production.');
  console.log();
  console.log(chalk.cyan(`  ${displayedCommand} test`));
  console.log('    Starts the test runner.');
  console.log();
  console.log(
    chalk.cyan(`  ${displayedCommand} ${useYarn ? '' : 'run '}eject`)
  );
  console.log(
    '    Removes this tool and copies build dependencies, configuration files'
  );
  console.log(
    '    and scripts into the app directory. If you do this, you can’t go back!'
  );
  console.log();
  console.log('We suggest that you begin by typing:');
  console.log();
  console.log(chalk.cyan('  cd'), cdpath);
  console.log(`  ${chalk.cyan(`${displayedCommand} start`)}`);
  if (readmeExists) {
    console.log();
    console.log(
      chalk.yellow(
        'You had a `README.md` file, we renamed it to `README.old.md`'
      )
    );
  }
  console.log();
  console.log('Happy hacking!');
};

function isReactInstalled(appPackage) {
  const dependencies = appPackage.dependencies || {};

  return (
    typeof dependencies.react !== 'undefined' &&
    typeof dependencies['react-dom'] !== 'undefined'
  );
}
<commit_msg>Whitelist main in template.json (#8539)<commit_after>// @remove-file-on-eject
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
'use strict';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

const fs = require('fs-extra');
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const execSync = require('child_process').execSync;
const spawn = require('react-dev-utils/crossSpawn');
const { defaultBrowsers } = require('react-dev-utils/browsersHelper');
const os = require('os');
const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup');

function isInGitRepository() {
  try {
    execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
    return true;
  } catch (e) {
    return false;
  }
}

function isInMercurialRepository() {
  try {
    execSync('hg --cwd . root', { stdio: 'ignore' });
    return true;
  } catch (e) {
    return false;
  }
}

function tryGitInit() {
  try {
    execSync('git --version', { stdio: 'ignore' });
    if (isInGitRepository() || isInMercurialRepository()) {
      return false;
    }

    execSync('git init', { stdio: 'ignore' });
    return true;
  } catch (e) {
    console.warn('Git repo not initialized', e);
    return false;
  }
}

function tryGitCommit(appPath) {
  try {
    execSync('git add -A', { stdio: 'ignore' });
    execSync('git commit -m "Initialize project using Create React App"', {
      stdio: 'ignore',
    });
    return true;
  } catch (e) {
    // We couldn't commit in already initialized git repo,
    // maybe the commit author config is not set.
    // In the future, we might supply our own committer
    // like Ember CLI does, but for now, let's just
    // remove the Git files to avoid a half-done state.
    console.warn('Git commit not created', e);
    console.warn('Removing .git directory...');
    try {
      // unlinkSync() doesn't work on directories.
      fs.removeSync(path.join(appPath, '.git'));
    } catch (removeErr) {
      // Ignore.
    }
    return false;
  }
}

module.exports = function(
  appPath,
  appName,
  verbose,
  originalDirectory,
  templateName
) {
  const appPackage = require(path.join(appPath, 'package.json'));
  const useYarn = fs.existsSync(path.join(appPath, 'yarn.lock'));

  if (!templateName) {
    console.log('');
    console.error(
      `A template was not provided. This is likely because you're using an outdated version of ${chalk.cyan(
        'create-react-app'
      )}.`
    );
    console.error(
      `Please note that global installs of ${chalk.cyan(
        'create-react-app'
      )} are no longer supported.`
    );
    return;
  }

  const templatePath = path.join(
    require.resolve(templateName, { paths: [appPath] }),
    '..'
  );

  let templateJsonPath;
  if (templateName) {
    templateJsonPath = path.join(templatePath, 'template.json');
  } else {
    // TODO: Remove support for this in v4.
    templateJsonPath = path.join(appPath, '.template.dependencies.json');
  }

  let templateJson = {};
  if (fs.existsSync(templateJsonPath)) {
    templateJson = require(templateJsonPath);
  }

  const templatePackage = templateJson.package || {};

  // Keys to ignore in templatePackage
  const templatePackageBlacklist = [
    'name',
    'version',
    'description',
    'keywords',
    'bugs',
    'license',
    'author',
    'contributors',
    'files',
    'browser',
    'bin',
    'man',
    'directories',
    'repository',
    'devDependencies',
    'peerDependencies',
    'bundledDependencies',
    'optionalDependencies',
    'engineStrict',
    'os',
    'cpu',
    'preferGlobal',
    'private',
    'publishConfig',
  ];

  // Keys from templatePackage that will be merged with appPackage
  const templatePackageToMerge = ['dependencies', 'scripts'];

  // Keys from templatePackage that will be added to appPackage,
  // replacing any existing entries.
  const templatePackageToReplace = Object.keys(templatePackage).filter(key => {
    return (
      !templatePackageBlacklist.includes(key) &&
      !templatePackageToMerge.includes(key)
    );
  });

  // Copy over some of the devDependencies
  appPackage.dependencies = appPackage.dependencies || {};

  // Setup the script rules
  // TODO: deprecate 'scripts' key directly on templateJson
  const templateScripts = templatePackage.scripts || templateJson.scripts || {};
  appPackage.scripts = Object.assign(
    {
      start: 'react-scripts start',
      build: 'react-scripts build',
      test: 'react-scripts test',
      eject: 'react-scripts eject',
    },
    templateScripts
  );

  // Update scripts for Yarn users
  if (useYarn) {
    appPackage.scripts = Object.entries(appPackage.scripts).reduce(
      (acc, [key, value]) => ({
        ...acc,
        [key]: value.replace(/(npm run |npm )/, 'yarn '),
      }),
      {}
    );
  }

  // Setup the eslint config
  appPackage.eslintConfig = {
    extends: 'react-app',
  };

  // Setup the browsers list
  appPackage.browserslist = defaultBrowsers;

  // Add templatePackage keys/values to appPackage, replacing existing entries
  templatePackageToReplace.forEach(key => {
    appPackage[key] = templatePackage[key];
  });

  fs.writeFileSync(
    path.join(appPath, 'package.json'),
    JSON.stringify(appPackage, null, 2) + os.EOL
  );

  const readmeExists = fs.existsSync(path.join(appPath, 'README.md'));
  if (readmeExists) {
    fs.renameSync(
      path.join(appPath, 'README.md'),
      path.join(appPath, 'README.old.md')
    );
  }

  // Copy the files for the user
  const templateDir = path.join(templatePath, 'template');
  if (fs.existsSync(templateDir)) {
    fs.copySync(templateDir, appPath);
  } else {
    console.error(
      `Could not locate supplied template: ${chalk.green(templateDir)}`
    );
    return;
  }

  // modifies README.md commands based on user used package manager.
  if (useYarn) {
    try {
      const readme = fs.readFileSync(path.join(appPath, 'README.md'), 'utf8');
      fs.writeFileSync(
        path.join(appPath, 'README.md'),
        readme.replace(/(npm run |npm )/g, 'yarn '),
        'utf8'
      );
    } catch (err) {
      // Silencing the error. As it fall backs to using default npm commands.
    }
  }

  const gitignoreExists = fs.existsSync(path.join(appPath, '.gitignore'));
  if (gitignoreExists) {
    // Append if there's already a `.gitignore` file there
    const data = fs.readFileSync(path.join(appPath, 'gitignore'));
    fs.appendFileSync(path.join(appPath, '.gitignore'), data);
    fs.unlinkSync(path.join(appPath, 'gitignore'));
  } else {
    // Rename gitignore after the fact to prevent npm from renaming it to .npmignore
    // See: https://github.com/npm/npm/issues/1862
    fs.moveSync(
      path.join(appPath, 'gitignore'),
      path.join(appPath, '.gitignore'),
      []
    );
  }

  // Initialize git repo
  let initializedGit = false;

  if (tryGitInit()) {
    initializedGit = true;
    console.log();
    console.log('Initialized a git repository.');
  }

  let command;
  let remove;
  let args;

  if (useYarn) {
    command = 'yarnpkg';
    remove = 'remove';
    args = ['add'];
  } else {
    command = 'npm';
    remove = 'uninstall';
    args = ['install', '--save', verbose && '--verbose'].filter(e => e);
  }

  // Install additional template dependencies, if present
  // TODO: deprecate 'dependencies' key directly on templateJson
  const templateDependencies =
    templatePackage.dependencies || templateJson.dependencies;
  if (templateDependencies) {
    args = args.concat(
      Object.keys(templateDependencies).map(key => {
        return `${key}@${templateDependencies[key]}`;
      })
    );
  }

  // Install react and react-dom for backward compatibility with old CRA cli
  // which doesn't install react and react-dom along with react-scripts
  if (!isReactInstalled(appPackage)) {
    args = args.concat(['react', 'react-dom']);
  }

  // Install template dependencies, and react and react-dom if missing.
  if ((!isReactInstalled(appPackage) || templateName) && args.length > 1) {
    console.log();
    console.log(`Installing template dependencies using ${command}...`);

    const proc = spawn.sync(command, args, { stdio: 'inherit' });
    if (proc.status !== 0) {
      console.error(`\`${command} ${args.join(' ')}\` failed`);
      return;
    }
  }

  if (args.find(arg => arg.includes('typescript'))) {
    console.log();
    verifyTypeScriptSetup();
  }

  // Remove template
  console.log(`Removing template package using ${command}...`);
  console.log();

  const proc = spawn.sync(command, [remove, templateName], {
    stdio: 'inherit',
  });
  if (proc.status !== 0) {
    console.error(`\`${command} ${args.join(' ')}\` failed`);
    return;
  }

  // Create git commit if git repo was initialized
  if (initializedGit && tryGitCommit(appPath)) {
    console.log();
    console.log('Created git commit.');
  }

  // Display the most elegant way to cd.
  // This needs to handle an undefined originalDirectory for
  // backward compatibility with old global-cli's.
  let cdpath;
  if (originalDirectory && path.join(originalDirectory, appName) === appPath) {
    cdpath = appName;
  } else {
    cdpath = appPath;
  }

  // Change displayed command to yarn instead of yarnpkg
  const displayedCommand = useYarn ? 'yarn' : 'npm';

  console.log();
  console.log(`Success! Created ${appName} at ${appPath}`);
  console.log('Inside that directory, you can run several commands:');
  console.log();
  console.log(chalk.cyan(`  ${displayedCommand} start`));
  console.log('    Starts the development server.');
  console.log();
  console.log(
    chalk.cyan(`  ${displayedCommand} ${useYarn ? '' : 'run '}build`)
  );
  console.log('    Bundles the app into static files for production.');
  console.log();
  console.log(chalk.cyan(`  ${displayedCommand} test`));
  console.log('    Starts the test runner.');
  console.log();
  console.log(
    chalk.cyan(`  ${displayedCommand} ${useYarn ? '' : 'run '}eject`)
  );
  console.log(
    '    Removes this tool and copies build dependencies, configuration files'
  );
  console.log(
    '    and scripts into the app directory. If you do this, you can’t go back!'
  );
  console.log();
  console.log('We suggest that you begin by typing:');
  console.log();
  console.log(chalk.cyan('  cd'), cdpath);
  console.log(`  ${chalk.cyan(`${displayedCommand} start`)}`);
  if (readmeExists) {
    console.log();
    console.log(
      chalk.yellow(
        'You had a `README.md` file, we renamed it to `README.old.md`'
      )
    );
  }
  console.log();
  console.log('Happy hacking!');
};

function isReactInstalled(appPackage) {
  const dependencies = appPackage.dependencies || {};

  return (
    typeof dependencies.react !== 'undefined' &&
    typeof dependencies['react-dom'] !== 'undefined'
  );
}
<|endoftext|>


<commit_before>import React from 'react'
import { storiesOf } from '@storybook/react'
import SettingsMenu from 'containers/Settings/SettingsMenu'
import { Provider } from '../Provider'
import { Window } from '../helpers'

storiesOf('Containers.SettingsMenu', module)
  .addDecorator(story => <Window>{story()}</Window>)
  .addDecorator(story => <Provider story={story()} />)
  .add('SettingsMenu', () => <SettingsMenu activeWalletSettings={{ id: 1, type: 'local' }} />)
<commit_msg>refactor: update storybook<commit_after>import React from 'react'
import { storiesOf } from '@storybook/react'
import SettingsMenu from 'containers/Settings/SettingsMenu'
import { Provider } from '../Provider'
import { Window } from '../helpers'

storiesOf('Containers.SettingsMenu', module)
  .addDecorator(story => <Window>{story()}</Window>)
  .addDecorator(story => <Provider story={story()} />)
  .add('SettingsMenu', () => (
    <SettingsMenu activeWalletSettings={{ id: 1, type: 'local' }} isWalletReady />
  ))
<|endoftext|>


<commit_before>'use strict';

angular.module('publicApp')
  .controller('UsersCtrl', ['$scope', '$http', '$location', '$route', '$routeParams', 'UserService', function ($scope, $http, $location, $route, $routeParams, $user) {
    $scope.user = $user;
    if ($user.isLogged) {
      if (($user.id == $routeParams.id) || $user.admin) {
        $scope.user.balances = [];
        $scope.user.ripple_transactions = [];
        $scope.user.external_transaction = [];
        $scope.user.external_accounts = [];
        $scope.user.ripple_addresses = [];

        getExternalTransactions();
        getRippleTransactions();
        getBalances();
        console.log($scope.user);
      } else {
        $location.path('/users/'+$user.id);
      }
    } else {
      $location.path('/login');
    }

    function getExternalTransactions() {
      $http.get('/api/v1/users/'+$user.id+'/external_transactions').success(function(resp){
        $scope.user.external_transactions = resp.external_transactions;
      });
    }

    function getRippleTransactions() {
      $http.get('/api/v1/users/'+$user.id+'/ripple_transactions').success(function(resp){
        $scope.user.ripple_transactions = resp.ripple_transactions;
      });
    }

    function getBalances() {
      $http.get('/api/v1/users/'+$user.id+'/balances').success(function(resp){
        $scope.user.balances = resp.balances;
      });
    }

  }]);
<commit_msg>[FEATURE] Update user links in angular to get resources.<commit_after>'use strict';

angular.module('publicApp')
  .controller('UsersCtrl', ['$scope', '$http', '$location', '$route', '$routeParams', 'UserService', function ($scope, $http, $location, $route, $routeParams, $user) {
    $scope.user = $user;
    if ($user.isLogged) {
      if (($user.id == $routeParams.id) || $user.admin) {
        $scope.user.balances = [];
        $scope.user.ripple_transactions = [];
        $scope.user.external_transaction = [];
        $scope.user.external_accounts = [];
        $scope.user.ripple_addresses = [];

        getExternalTransactions();
        getRippleTransactions();
        getBalances();
        console.log($scope.user);
      } else {
        $location.path('/users/'+$user.id);
      }
    } else {
      $location.path('/login');
    }

    function getExternalTransactions() {
      $http.get('/api/v1/external_transactions').success(function(resp){
        $scope.user.external_transactions = resp.external_transactions;
      });
    }

    function getRippleTransactions() {
      $http.get('/api/v1/ripple_transactions').success(function(resp){
        $scope.user.ripple_transactions = resp.ripple_transactions;
      });
    }

    function getBalances() {
      $http.get('/api/v1/balances').success(function(resp){
        $scope.user.balances = resp.balances;
      });
    }

  }]);
<|endoftext|>


<commit_before>const {
  declareInjections,
  getOwner,
  setOwner
} = require('@cardstack/di');
const path = require('path');
const log = require('@cardstack/logger')('cardstack/plugin-loader');
const denodeify = require('denodeify');
const resolve = denodeify(require('resolve'));
const fs = require('fs');
const realpath = denodeify(fs.realpath);
const readdir = denodeify(fs.readdir);
const Error = require('@cardstack/plugin-utils/error');
const { get } = require('lodash');

log.registerFormatter('t', require('./table-log-formatter'));

const featureTypes = [
  'constraint-types',
  'field-types',
  'computed-field-types',
  'writers',
  'searchers',
  'indexers',
  'static-models',
  'authenticators',
  'middleware',
  'routers',
  'messengers',
  'code-generators'
];
const javascriptPattern = /(.*)\.js$/;

module.exports = declareInjections({
  project: 'config:project',
  environment: 'config:environment'
},

class PluginLoader {
  static create(opts) {
    return new this(opts);
  }

  constructor({ project, environment }) {
    if (!project) {
      throw new Error("Missing configuration `config:project`");
    }

    if (!project.path) {
      throw new Error("`config:project` must have a `path`");
    }
    this.project = project;
    this.environment = get(environment, 'name');
    this._pluginsAndFeatures = null;
  }

  async _findPluginsAndFeatures() {
    let output = [];
    let seen = Object.create(null);

    let projectPath = path.resolve(this.project.path);
    log.info("starting from path %s", projectPath);

    // at the top-level (the project itself) we always include dev
    // deps. Not doing so under some conditions would be too big a
    // troll.
    let includeDevDependencies = true;

    await this._crawlPlugins(projectPath, output, seen, includeDevDependencies, []);

    let allFeatures = [];
    for (let plugin of output) {
      let features = await discoverFeatures(plugin.attributes.dir, plugin.id);
      plugin.relationships = {
        features: {
          data: features.map(({ type, id }) => ({ type, id }))
        },
        config: {
          data: { type: 'plugin-configs', id: plugin.id }
        }
      };
      allFeatures = allFeatures.concat(features);
    }
    log.info("=== found installed plugins===\n%t", () => summarize(output, allFeatures));
    return { installedPlugins: output, installedFeatures: allFeatures };
  }

  async installedPlugins() {
    if (!this._pluginsAndFeatures) {
      this._pluginsAndFeatures = this._findPluginsAndFeatures();
    }
    return (await this._pluginsAndFeatures).installedPlugins;
  }

  async installedFeatures() {
    if (!this._pluginsAndFeatures) {
      this._pluginsAndFeatures = this._findPluginsAndFeatures();
    }
    return (await this._pluginsAndFeatures).installedFeatures;
  }

  async configuredPlugins(configModels) {
    let configs = new Map();
    for (let model of configModels) {
      configs.set(model.id, model);
    }
    let installed = await this.installedPlugins();

    let missing = missingPlugins(installed, configs);
    if (missing.length > 0) {
      log.warn("Plugins are configured but not installed: %j", missing);
    }
    activateRecursively(installed, configs);
    let a = new ConfiguredPlugins(installed, await this.installedFeatures(), configs);
    setOwner(a, getOwner(this));
    return a;
  }

  async _crawlPlugins(dir, outputPlugins, seen, includeDevDependencies, breadcrumbs) {
    log.trace("plugin crawl dir=%s, includeDevDependencies=%s, breadcrumbs=%j", dir, includeDevDependencies, breadcrumbs);

    let realdir = await realpath(dir);
    if (seen[realdir]) {
      if (get(seen, `${dir}.attributes.includedFrom`)) {
        // if we've seen this dir before *and* it's a cardstack
        // plugin, we should update its includedFrom to include the
        // new path that we arrived by
        seen[realdir].attributes.includedFrom.push(breadcrumbs);
      }
      return;
    }

    let packageJSON = path.join(realdir, 'package.json');
    let json = require(packageJSON);
    let dupeModule = Object.values(seen).find(i => i.id === json.name);
    if (dupeModule) {
      let msg = action => `The plugin module name '${json.name}' has already been loaded from the module path ${dupeModule.attributes.rawDir}, ${action} load of module at path ${dir}.`;
      if (this.environment === 'test') {
        throw new Error(msg('conflict with'));
      }

      log.warn(msg('skipping'));

      if (get(dupeModule, 'attributes.includedFrom')) {
        dupeModule.attributes.includedFrom.push(breadcrumbs);
      }

      return;
    }

    seen[realdir] = true;
    let moduleRoot = path.dirname(await resolve(packageJSON, { basedir: this.project.path }));

    if (json.keywords && json.keywords.includes('cardstack-plugin') && json['cardstack-plugin']) {
      if (json['cardstack-plugin']['api-version'] !== 1) {
        log.warn(`%s has some fancy cardstack-plugin.version I don't understand. Trying anyway.`, realdir);
      }
      let customSource = json['cardstack-plugin'].src;
      if (customSource) {
        moduleRoot = path.join(moduleRoot, customSource);
      }
    } else {
      // top-level app doesn't need to be a cardstack-plugin, but when
      // crawling any deeper dependencies we only care about them if
      // they are cardstack-plugins.
      if (breadcrumbs.length > 0) {
        log.trace(`%s does not appear to contain a cardstack plugin`, realdir);
        return;
      }
    }

    seen[realdir] = {
      id: json.name,
      type: 'plugins',
      attributes: {
        dir: moduleRoot,
        rawDir: dir,
        includedFrom: [breadcrumbs]
      }
    };

    outputPlugins.push(seen[realdir]);

    let deps = json.dependencies ? Object.keys(json.dependencies).map(dep => ({ dep, type: 'dependencies' })) : [];
    if (includeDevDependencies && json.devDependencies) {
      deps = deps.concat(Object.keys(json.devDependencies).map(dep => ({ dep, type: 'devDependencies' })));
    }

    if (json['cardstack-plugin']) {
      let dirs = json['cardstack-plugin']['in-repo-plugins'];
      if (dirs) {
        deps = deps.concat(dirs.map(dir => ({ dep: path.resolve(moduleRoot + '/' + dir), type: 'in-repo-plugins' })));
      }
    }

    for (let { dep, type } of deps) {
      let childDir = path.dirname(await resolve(dep + '/package.json', { basedir: realdir }));

      // we never include devDependencies of second level (or deeper) dependencies
      let includeDevDependencies = false;
      await this._crawlPlugins(childDir, outputPlugins, seen, includeDevDependencies, breadcrumbs.concat({ id: json.name, type }));
    }
  }

  static types() {
    return featureTypes;
  }

});

async function discoverFeatures(moduleRoot, pluginName) {
  log.trace('Discovering features in plugin %s (%s)', pluginName, moduleRoot);

  let features = [];
  for (let featureType of featureTypes) {
    try {
      let folderPath = path.join(moduleRoot, featureType);
      log.trace('-- Looking for folder: %s', folderPath);

      let files = await readdir(folderPath);
      for (let file of files) {
        log.trace('---- Found file: %s', file);

        let m = javascriptPattern.exec(file);
        if (m) {
          let id = `${pluginName}::${m[1]}`;
          let loadPath = path.join(moduleRoot, featureType, file);

          log.trace('---- Adding %s feature: %s (%s)', featureType, id, loadPath);

          features.push({
            id,
            type: featureType,
            attributes: {
              'load-path': loadPath
            },
            relationships: {
              plugin: {
                data: { type: 'plugins', id: pluginName }
              }
            }
          });
        }
      }
    } catch (err) {
      if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
        throw err;
      }
    }

    let filename = path.join(moduleRoot, singularize(featureType) + '.js');
    log.trace('-- Looking for file: %s', filename);

    if (fs.existsSync(filename)) {
      log.trace('---- Adding %s feature: %s (%s)', featureType, pluginName, filename);

      features.push({
        id: pluginName,
        type: featureType,
        attributes: {
          'load-path': filename
        },
        relationships: {
          plugin: {
            data: { type: 'plugins', id: pluginName }
          }
        }
      });
    }
  }
  return features;
}

function singularize(name) {
  return name.replace(/s$/, '');
}

class ConfiguredPlugins {
  constructor(installedPlugins, installedFeatures, configs) {
    this.rootPlugin = Object.create(null);
    this._plugins = Object.create(null);
    this._features = Object.create(null);

    installedPlugins.forEach(plugin => {
      let copied = Object.assign({}, plugin);
      let config = configs.get(plugin.id);
      if (config) {
        copied.attributes = Object.assign({}, plugin.attributes, config.attributes);
        if (copied.attributes.enabled !== false) {
          copied.attributes.enabled = true;
        }
        copied.relationships = Object.assign({}, plugin.relationships, config.relationships);
      } else {
        copied.attributes = Object.assign({}, plugin.attributes);
        copied.attributes.enabled = true;
      }
      this._plugins[copied.id] = copied;
    });

    featureTypes.forEach(type => this._features[type] = Object.create(null));

    installedFeatures.forEach(feature => {
      this._features[feature.type][feature.id] = feature;
    });
  }

  describeAll() {
    if (!this._describeAllCache) {
      this._describeAllCache = Object.values(this._plugins);
    }
    return this._describeAllCache;
  }

  describe(pluginName) {
    return this._plugins[pluginName];
  }

  describeFeature(featureType, featureName) {
    let typeSet = this._features[featureType];
    if (!typeSet) {
      throw new Error(`No such feature type "${featureType}"`);
    }
    return typeSet[featureName];
  }

  lookupFeature(featureType, fullyQualifiedName)  {
    return this._instance(this._lookupFeature(featureType, fullyQualifiedName));
  }

  lookupFeatureFactory(featureType, fullyQualifiedName)  {
    return this._factory(this._lookupFeature(featureType, fullyQualifiedName));
  }

  lookupFeatureAndAssert(featureType, fullyQualifiedName)  {
    return this._instance(this._lookupFeatureAndAssert(featureType, fullyQualifiedName));
  }

  lookupFeatureFactoryAndAssert(featureType, fullyQualifiedName)  {
    return this._factory(this._lookupFeatureAndAssert(featureType, fullyQualifiedName));
  }

  featuresOfType(featureType) {
    let typeSet = this._features[featureType];
    if (!typeSet) {
      throw new Error(`No such feature type "${featureType}"`);
    } else {
      return Object.values(typeSet).filter(feature => this._plugins[feature.relationships.plugin.data.id].attributes.enabled);
    }
  }

  _instance(resolverName) {
    if (resolverName) {
      return getOwner(this).lookup(resolverName);
    }
  }

  _factory(resolverName) {
    if (resolverName) {
      return getOwner(this).factoryFor(resolverName);
    }
  }

  _lookupFeature(featureType, fullyQualifiedName)  {
    let typeSet = this._features[featureType];
    if (typeSet) {
      let feature = typeSet[fullyQualifiedName];
      if (feature) {
        if (this._plugins[feature.relationships.plugin.data.id].attributes.enabled) {
          return resolverName(feature);
        }
      }
    }
  }

  _lookupFeatureAndAssert(featureType, fullyQualifiedName)  {
    let typeSet = this._features[featureType];
    if (typeSet) {
      let feature = typeSet[fullyQualifiedName];
      if (feature) {
        if (this._plugins[feature.relationships.plugin.data.id].attributes.enabled) {
          return resolverName(feature);
        } else {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but the plugin ${feature.relationships.plugin.data.id} is not activated`);
        }
      } else {
        let [moduleName] = fullyQualifiedName.split('::');
        if (this._plugins[moduleName]) {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but no such feature exists in plugin ${moduleName}`);
        } else {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but the plugin ${moduleName} is not installed. Make sure it appears in the dependencies section of package.json`);
        }
      }
    } else {
      throw new Error(`No such feature type "${featureType}"`);
    }
  }

}

function resolverName(feature) {
  let attrs = feature.attributes;
  return `plugin-${feature.type}:${attrs['load-path']}`;
}

function missingPlugins(installed, configs) {
  let missing = [];
  for (let pluginName of configs.keys()) {
    if (!installed.find(p => p.id === pluginName)) {
      missing.push(pluginName);
    }
  }
  return missing;
}

function summarize(plugins, features) {
  return plugins.map(p => {
    let pluginFeatures = features.filter(f => f.relationships.plugin.data.id === p.id);
    if (pluginFeatures.length > 0){
      return pluginFeatures.map(f => [p.id, f.type, f.id]);
    } else {
      return [[p.id, '']];
    }
  }).reduce((a,b) => a.concat(b), []);
}

function activateRecursively(installed, configs) {
  // The hub is always active, it doesn't really make sense to be here
  // if it isn't.
  if (!configs.get('@cardstack/hub')) {
    configs.set('@cardstack/hub', { moduleName: '@cardstack/hub' });
  }

  let dependsOn = dependencyGraph(installed);
  let queue = [...configs.keys()];
  let seen = Object.create(null);
  while (queue.length > 0) {
    let pluginName = queue.shift();
    if (seen[pluginName]) { continue; }
    seen[pluginName] = true;
    let deps = dependsOn[pluginName];
    if (deps) {
      for (let dep of deps) {
        if (!configs.get(dep)) {
          log.debug('Activating plugin %s because its used by %s', dep, pluginName);
          configs.set(dep, { moduleName: dep });
          queue.push(dep);
        }
      }
    }
  }
}

// This only includes "dependencies", not "devDependencies" or
// "in-repo-plugins" (only "dependencies" are things that must always
// be both installed and active when you are active).
function dependencyGraph(installed) {
  let dependsOn = Object.create(null);
  for (let plugin of installed) {
    for (let breadcrumbs of plugin.attributes.includedFrom) {
      let parent = breadcrumbs[breadcrumbs.length - 1];
      if (!parent || parent.type !== 'dependencies') { continue; }
      if (!dependsOn[parent.id]) {
        dependsOn[parent.id] = [ plugin.id ];
      } else {
        dependsOn[parent.id].push(plugin.id);
      }
    }
  }
  log.debug('=== plugin dependency graph ===\n%t', () => Object.keys(dependsOn).map(k => dependsOn[k].map(v => [k,v])).reduce((a,b) => a.concat(b)));
  return dependsOn;
}
<commit_msg>removing zombie code, routers are content-type attributes now, not hub features<commit_after>const {
  declareInjections,
  getOwner,
  setOwner
} = require('@cardstack/di');
const path = require('path');
const log = require('@cardstack/logger')('cardstack/plugin-loader');
const denodeify = require('denodeify');
const resolve = denodeify(require('resolve'));
const fs = require('fs');
const realpath = denodeify(fs.realpath);
const readdir = denodeify(fs.readdir);
const Error = require('@cardstack/plugin-utils/error');
const { get } = require('lodash');

log.registerFormatter('t', require('./table-log-formatter'));

const featureTypes = [
  'constraint-types',
  'field-types',
  'computed-field-types',
  'writers',
  'searchers',
  'indexers',
  'static-models',
  'authenticators',
  'middleware',
  'messengers',
  'code-generators'
];
const javascriptPattern = /(.*)\.js$/;

module.exports = declareInjections({
  project: 'config:project',
  environment: 'config:environment'
},

class PluginLoader {
  static create(opts) {
    return new this(opts);
  }

  constructor({ project, environment }) {
    if (!project) {
      throw new Error("Missing configuration `config:project`");
    }

    if (!project.path) {
      throw new Error("`config:project` must have a `path`");
    }
    this.project = project;
    this.environment = get(environment, 'name');
    this._pluginsAndFeatures = null;
  }

  async _findPluginsAndFeatures() {
    let output = [];
    let seen = Object.create(null);

    let projectPath = path.resolve(this.project.path);
    log.info("starting from path %s", projectPath);

    // at the top-level (the project itself) we always include dev
    // deps. Not doing so under some conditions would be too big a
    // troll.
    let includeDevDependencies = true;

    await this._crawlPlugins(projectPath, output, seen, includeDevDependencies, []);

    let allFeatures = [];
    for (let plugin of output) {
      let features = await discoverFeatures(plugin.attributes.dir, plugin.id);
      plugin.relationships = {
        features: {
          data: features.map(({ type, id }) => ({ type, id }))
        },
        config: {
          data: { type: 'plugin-configs', id: plugin.id }
        }
      };
      allFeatures = allFeatures.concat(features);
    }
    log.info("=== found installed plugins===\n%t", () => summarize(output, allFeatures));
    return { installedPlugins: output, installedFeatures: allFeatures };
  }

  async installedPlugins() {
    if (!this._pluginsAndFeatures) {
      this._pluginsAndFeatures = this._findPluginsAndFeatures();
    }
    return (await this._pluginsAndFeatures).installedPlugins;
  }

  async installedFeatures() {
    if (!this._pluginsAndFeatures) {
      this._pluginsAndFeatures = this._findPluginsAndFeatures();
    }
    return (await this._pluginsAndFeatures).installedFeatures;
  }

  async configuredPlugins(configModels) {
    let configs = new Map();
    for (let model of configModels) {
      configs.set(model.id, model);
    }
    let installed = await this.installedPlugins();

    let missing = missingPlugins(installed, configs);
    if (missing.length > 0) {
      log.warn("Plugins are configured but not installed: %j", missing);
    }
    activateRecursively(installed, configs);
    let a = new ConfiguredPlugins(installed, await this.installedFeatures(), configs);
    setOwner(a, getOwner(this));
    return a;
  }

  async _crawlPlugins(dir, outputPlugins, seen, includeDevDependencies, breadcrumbs) {
    log.trace("plugin crawl dir=%s, includeDevDependencies=%s, breadcrumbs=%j", dir, includeDevDependencies, breadcrumbs);

    let realdir = await realpath(dir);
    if (seen[realdir]) {
      if (get(seen, `${dir}.attributes.includedFrom`)) {
        // if we've seen this dir before *and* it's a cardstack
        // plugin, we should update its includedFrom to include the
        // new path that we arrived by
        seen[realdir].attributes.includedFrom.push(breadcrumbs);
      }
      return;
    }

    let packageJSON = path.join(realdir, 'package.json');
    let json = require(packageJSON);
    let dupeModule = Object.values(seen).find(i => i.id === json.name);
    if (dupeModule) {
      let msg = action => `The plugin module name '${json.name}' has already been loaded from the module path ${dupeModule.attributes.rawDir}, ${action} load of module at path ${dir}.`;
      if (this.environment === 'test') {
        throw new Error(msg('conflict with'));
      }

      log.warn(msg('skipping'));

      if (get(dupeModule, 'attributes.includedFrom')) {
        dupeModule.attributes.includedFrom.push(breadcrumbs);
      }

      return;
    }

    seen[realdir] = true;
    let moduleRoot = path.dirname(await resolve(packageJSON, { basedir: this.project.path }));

    if (json.keywords && json.keywords.includes('cardstack-plugin') && json['cardstack-plugin']) {
      if (json['cardstack-plugin']['api-version'] !== 1) {
        log.warn(`%s has some fancy cardstack-plugin.version I don't understand. Trying anyway.`, realdir);
      }
      let customSource = json['cardstack-plugin'].src;
      if (customSource) {
        moduleRoot = path.join(moduleRoot, customSource);
      }
    } else {
      // top-level app doesn't need to be a cardstack-plugin, but when
      // crawling any deeper dependencies we only care about them if
      // they are cardstack-plugins.
      if (breadcrumbs.length > 0) {
        log.trace(`%s does not appear to contain a cardstack plugin`, realdir);
        return;
      }
    }

    seen[realdir] = {
      id: json.name,
      type: 'plugins',
      attributes: {
        dir: moduleRoot,
        rawDir: dir,
        includedFrom: [breadcrumbs]
      }
    };

    outputPlugins.push(seen[realdir]);

    let deps = json.dependencies ? Object.keys(json.dependencies).map(dep => ({ dep, type: 'dependencies' })) : [];
    if (includeDevDependencies && json.devDependencies) {
      deps = deps.concat(Object.keys(json.devDependencies).map(dep => ({ dep, type: 'devDependencies' })));
    }

    if (json['cardstack-plugin']) {
      let dirs = json['cardstack-plugin']['in-repo-plugins'];
      if (dirs) {
        deps = deps.concat(dirs.map(dir => ({ dep: path.resolve(moduleRoot + '/' + dir), type: 'in-repo-plugins' })));
      }
    }

    for (let { dep, type } of deps) {
      let childDir = path.dirname(await resolve(dep + '/package.json', { basedir: realdir }));

      // we never include devDependencies of second level (or deeper) dependencies
      let includeDevDependencies = false;
      await this._crawlPlugins(childDir, outputPlugins, seen, includeDevDependencies, breadcrumbs.concat({ id: json.name, type }));
    }
  }

  static types() {
    return featureTypes;
  }

});

async function discoverFeatures(moduleRoot, pluginName) {
  log.trace('Discovering features in plugin %s (%s)', pluginName, moduleRoot);

  let features = [];
  for (let featureType of featureTypes) {
    try {
      let folderPath = path.join(moduleRoot, featureType);
      log.trace('-- Looking for folder: %s', folderPath);

      let files = await readdir(folderPath);
      for (let file of files) {
        log.trace('---- Found file: %s', file);

        let m = javascriptPattern.exec(file);
        if (m) {
          let id = `${pluginName}::${m[1]}`;
          let loadPath = path.join(moduleRoot, featureType, file);

          log.trace('---- Adding %s feature: %s (%s)', featureType, id, loadPath);

          features.push({
            id,
            type: featureType,
            attributes: {
              'load-path': loadPath
            },
            relationships: {
              plugin: {
                data: { type: 'plugins', id: pluginName }
              }
            }
          });
        }
      }
    } catch (err) {
      if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
        throw err;
      }
    }

    let filename = path.join(moduleRoot, singularize(featureType) + '.js');
    log.trace('-- Looking for file: %s', filename);

    if (fs.existsSync(filename)) {
      log.trace('---- Adding %s feature: %s (%s)', featureType, pluginName, filename);

      features.push({
        id: pluginName,
        type: featureType,
        attributes: {
          'load-path': filename
        },
        relationships: {
          plugin: {
            data: { type: 'plugins', id: pluginName }
          }
        }
      });
    }
  }
  return features;
}

function singularize(name) {
  return name.replace(/s$/, '');
}

class ConfiguredPlugins {
  constructor(installedPlugins, installedFeatures, configs) {
    this.rootPlugin = Object.create(null);
    this._plugins = Object.create(null);
    this._features = Object.create(null);

    installedPlugins.forEach(plugin => {
      let copied = Object.assign({}, plugin);
      let config = configs.get(plugin.id);
      if (config) {
        copied.attributes = Object.assign({}, plugin.attributes, config.attributes);
        if (copied.attributes.enabled !== false) {
          copied.attributes.enabled = true;
        }
        copied.relationships = Object.assign({}, plugin.relationships, config.relationships);
      } else {
        copied.attributes = Object.assign({}, plugin.attributes);
        copied.attributes.enabled = true;
      }
      this._plugins[copied.id] = copied;
    });

    featureTypes.forEach(type => this._features[type] = Object.create(null));

    installedFeatures.forEach(feature => {
      this._features[feature.type][feature.id] = feature;
    });
  }

  describeAll() {
    if (!this._describeAllCache) {
      this._describeAllCache = Object.values(this._plugins);
    }
    return this._describeAllCache;
  }

  describe(pluginName) {
    return this._plugins[pluginName];
  }

  describeFeature(featureType, featureName) {
    let typeSet = this._features[featureType];
    if (!typeSet) {
      throw new Error(`No such feature type "${featureType}"`);
    }
    return typeSet[featureName];
  }

  lookupFeature(featureType, fullyQualifiedName)  {
    return this._instance(this._lookupFeature(featureType, fullyQualifiedName));
  }

  lookupFeatureFactory(featureType, fullyQualifiedName)  {
    return this._factory(this._lookupFeature(featureType, fullyQualifiedName));
  }

  lookupFeatureAndAssert(featureType, fullyQualifiedName)  {
    return this._instance(this._lookupFeatureAndAssert(featureType, fullyQualifiedName));
  }

  lookupFeatureFactoryAndAssert(featureType, fullyQualifiedName)  {
    return this._factory(this._lookupFeatureAndAssert(featureType, fullyQualifiedName));
  }

  featuresOfType(featureType) {
    let typeSet = this._features[featureType];
    if (!typeSet) {
      throw new Error(`No such feature type "${featureType}"`);
    } else {
      return Object.values(typeSet).filter(feature => this._plugins[feature.relationships.plugin.data.id].attributes.enabled);
    }
  }

  _instance(resolverName) {
    if (resolverName) {
      return getOwner(this).lookup(resolverName);
    }
  }

  _factory(resolverName) {
    if (resolverName) {
      return getOwner(this).factoryFor(resolverName);
    }
  }

  _lookupFeature(featureType, fullyQualifiedName)  {
    let typeSet = this._features[featureType];
    if (typeSet) {
      let feature = typeSet[fullyQualifiedName];
      if (feature) {
        if (this._plugins[feature.relationships.plugin.data.id].attributes.enabled) {
          return resolverName(feature);
        }
      }
    }
  }

  _lookupFeatureAndAssert(featureType, fullyQualifiedName)  {
    let typeSet = this._features[featureType];
    if (typeSet) {
      let feature = typeSet[fullyQualifiedName];
      if (feature) {
        if (this._plugins[feature.relationships.plugin.data.id].attributes.enabled) {
          return resolverName(feature);
        } else {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but the plugin ${feature.relationships.plugin.data.id} is not activated`);
        }
      } else {
        let [moduleName] = fullyQualifiedName.split('::');
        if (this._plugins[moduleName]) {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but no such feature exists in plugin ${moduleName}`);
        } else {
          throw new Error(`You're trying to use ${featureType} ${fullyQualifiedName} but the plugin ${moduleName} is not installed. Make sure it appears in the dependencies section of package.json`);
        }
      }
    } else {
      throw new Error(`No such feature type "${featureType}"`);
    }
  }

}

function resolverName(feature) {
  let attrs = feature.attributes;
  return `plugin-${feature.type}:${attrs['load-path']}`;
}

function missingPlugins(installed, configs) {
  let missing = [];
  for (let pluginName of configs.keys()) {
    if (!installed.find(p => p.id === pluginName)) {
      missing.push(pluginName);
    }
  }
  return missing;
}

function summarize(plugins, features) {
  return plugins.map(p => {
    let pluginFeatures = features.filter(f => f.relationships.plugin.data.id === p.id);
    if (pluginFeatures.length > 0){
      return pluginFeatures.map(f => [p.id, f.type, f.id]);
    } else {
      return [[p.id, '']];
    }
  }).reduce((a,b) => a.concat(b), []);
}

function activateRecursively(installed, configs) {
  // The hub is always active, it doesn't really make sense to be here
  // if it isn't.
  if (!configs.get('@cardstack/hub')) {
    configs.set('@cardstack/hub', { moduleName: '@cardstack/hub' });
  }

  let dependsOn = dependencyGraph(installed);
  let queue = [...configs.keys()];
  let seen = Object.create(null);
  while (queue.length > 0) {
    let pluginName = queue.shift();
    if (seen[pluginName]) { continue; }
    seen[pluginName] = true;
    let deps = dependsOn[pluginName];
    if (deps) {
      for (let dep of deps) {
        if (!configs.get(dep)) {
          log.debug('Activating plugin %s because its used by %s', dep, pluginName);
          configs.set(dep, { moduleName: dep });
          queue.push(dep);
        }
      }
    }
  }
}

// This only includes "dependencies", not "devDependencies" or
// "in-repo-plugins" (only "dependencies" are things that must always
// be both installed and active when you are active).
function dependencyGraph(installed) {
  let dependsOn = Object.create(null);
  for (let plugin of installed) {
    for (let breadcrumbs of plugin.attributes.includedFrom) {
      let parent = breadcrumbs[breadcrumbs.length - 1];
      if (!parent || parent.type !== 'dependencies') { continue; }
      if (!dependsOn[parent.id]) {
        dependsOn[parent.id] = [ plugin.id ];
      } else {
        dependsOn[parent.id].push(plugin.id);
      }
    }
  }
  log.debug('=== plugin dependency graph ===\n%t', () => Object.keys(dependsOn).map(k => dependsOn[k].map(v => [k,v])).reduce((a,b) => a.concat(b)));
  return dependsOn;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

define(function() {
  /**
   * Converts an RGB color value to HSV. Conversion formula
   * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
   * Assumes r, g, and b are contained in the set [0, 255] and
   * returns h, s, and v in the set [0, 1].
   *
   * @param {number} r The red color value
   * @param {number} g The green color value
   * @param {number} b The blue color value
   * @return {!Array.<number>} The HSV representation
   */
  var rgbToHsv = function(r, g, b) {
    r = r / 255;
    g = g / 255;
    b = b / 255;
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    var h;
    var s;
    var v = max;

    var d = max - min;
    s = max == 0 ? 0 : d / max;

    if (max == min) {
      h = 0; // achromatic
    } else {
      switch(max) {
        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
        case g: h = (b - r) / d + 2; break;
        case b: h = (r - g) / d + 4; break;
      }
      h /= 6;
    }

    return [h, s, v];
  };

  /**
   * Converts an HSV color value to RGB. Conversion formula
   * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
   * Assumes h, s, and v are contained in the set [0, 1] and
   * returns r, g, and b in the set [0, 255].
   *
   * @param {number} h The hue
   * @param {number} s The saturation
   * @param {number} v The value
   * @return {!Array.<number>} The RGB representation
   */
  var hsvToRgb = function(h, s, v) {
    var r;
    var g;
    var b;

    var i = Math.floor(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);

    switch(i % 6) {
      case 0: r = v, g = t, b = p; break;
      case 1: r = q, g = v, b = p; break;
      case 2: r = p, g = v, b = t; break;
      case 3: r = p, g = q, b = v; break;
      case 4: r = t, g = p, b = v; break;
      case 5: r = v, g = p, b = q; break;
    }

    return [r * 255, g * 255, b * 255];
  };

  /**
   * Adjusts the hue, saturation and value of an image.
   * @param {!Image} image an Image tag
   * @param {number} hue The amount to adjust the hue.
   * @param {number} saturation The amount to adjust the
   *     saturation.
   * @param {number} value. The amount to adjust the value.
   *     image
   * @param {number} opt_hueRangeLimit. Defines a hue range,
   *        Pixels outside this range will not be adjusted. Note:
   *        the first value is the starting hue and the second
   *        the ending hue. So [0.1, 0.2] adjusts pixels with hues
   *        between 0.1<->0.2 where as [0.2,0.1] adjusts pixels
   *        with hues from 0.2<->1.0 and 0.0<->0.1. In other words
   *        only 0.1<->0.2 will not be adjusted.
   *
   *        What's the point? Let's say you have a character with
   *        blue shirt and a pink face. If you adjust all the
   *        colors the face would change from pink. If you select
   *        a range that covers only blue then only the blue
   *        pixels will be adjusted letting you adjust only the
   *        shirt.
   *
   *        To figure out the ranges use photoshop's
   *        hue/saturation layer. Near the top of the settings
   *        pick the drop down "Master", pick a color, the adjust
   *        the sliders. Photoshop gives the settings in degrees
   *        so you'll have to convert to 0 to 1 (eg,
   *        photoshopValue / 360)
   *
   * @return {!Canvas} a canvas element with the adjusted image.
   */
  var adjustHSV = function(image, hue, saturation, value, opt_hueRangeLimit) {
    opt_hueRangeLimit = opt_hueRangeLimit || [0, 1];
    var minHue = (opt_hueRangeLimit[0] + 0.0) % 1;
    var maxHue = (opt_hueRangeLimit[1] + 0.0) % 1;

    // |<------------>|
    //    min     max      min<->mz
    //
    //    max     min      min->1  0->max

    var minLessThanMax = function(v) {
      return v >= minHue && v <= maxHue;
    };

    var maxLessThanMin = function(v) {
      return v >= minHue || v <= maxHue;
    };

    var validHue = minHue < maxHue ? minLessThanMax : maxLessThanMin;
    var canvas = document.createElement("canvas");
    var width = image.width;
    var height = image.height;
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    var imageData = ctx.getImageData(0, 0, width, height);
    var pixels = imageData.data;
    var numPixels = width * height;
    var numBytes = numPixels * 4;
    for (var offset = 0; offset < numBytes; offset += 4) {
      var hsv = rgbToHsv(pixels[offset + 0], pixels[offset + 1], pixels[offset + 2]);
      if (!validHue(hsv[0])) {
        continue;
      }
      var h = (hsv[0] + hue + 100) % 1;
      var s = Math.min(1, Math.max(0, hsv[1] + saturation));
      var v = Math.min(1, Math.max(0, hsv[2] + value));
      var rgb = hsvToRgb(h, s, v);
      pixels[offset + 0] = rgb[0];
      pixels[offset + 1] = rgb[1];
      pixels[offset + 2] = rgb[2];
    }
    ctx.putImageData(imageData, 0, 0);
    return canvas;
  };

  // Returns a canvas with the cropped piece only.
  // @param {!Image|!Canvas} src image or canvas to crop
  // @param {number} x left
  // @param {number} y top
  // @param {number} width width
  // @param {number} height height
  var cropImage = function(src, x, y, width, height) {
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(src, x, y, width, height, 0, 0, width, height);
    return canvas;
  };

  // Returns a scaled canvas using nearest neighbor.
  // @param {!Image|!Canvas} src image or canvas to scale
  // @param {number} newWidth width
  // @param {number} newHeight height
  var scaleImage = function(src, newWidth, newHeight) {
    var canvas = document.createElement("canvas");
    canvas.width = src.width;
    canvas.height = src.height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(src, 0, 0);
    var srcImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var srcPixels = srcImageData.data;
    canvas.width = newWidth;
    canvas.height = newHeight;
    var dstImageData = ctx.createImageData(newWidth, newHeight);
    var dstPixels = dstImageData.data;
    for (var y = 0; y < newHeight; ++y) {
      var srcY = (y * src.height / newHeight) | 0;
      var dstOffset = y * newWidth * 4;
      for (var x = 0; x < newWidth; ++x) {
        var srcX = (x * src.width / newWidth) | 0;
        var srcOffset = (srcY * src.width + srcX) * 4;
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
      }
    }
    ctx.putImageData(dstImageData, 0, 0);
    return canvas;
  };

  return {
      adjustHSV: adjustHSV,
      cropImage: cropImage,
      scaleImage: scaleImage,
  };
});
<commit_msg>Add function to make text image from string<commit_after>/*
 * Copyright 2014, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

define(function() {
  /**
   * Converts an RGB color value to HSV. Conversion formula
   * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
   * Assumes r, g, and b are contained in the set [0, 255] and
   * returns h, s, and v in the set [0, 1].
   *
   * @param {number} r The red color value
   * @param {number} g The green color value
   * @param {number} b The blue color value
   * @return {!Array.<number>} The HSV representation
   */
  var rgbToHsv = function(r, g, b) {
    r = r / 255;
    g = g / 255;
    b = b / 255;
    var max = Math.max(r, g, b);
    var min = Math.min(r, g, b);
    var h;
    var s;
    var v = max;

    var d = max - min;
    s = max == 0 ? 0 : d / max;

    if (max == min) {
      h = 0; // achromatic
    } else {
      switch(max) {
        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
        case g: h = (b - r) / d + 2; break;
        case b: h = (r - g) / d + 4; break;
      }
      h /= 6;
    }

    return [h, s, v];
  };

  /**
   * Converts an HSV color value to RGB. Conversion formula
   * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
   * Assumes h, s, and v are contained in the set [0, 1] and
   * returns r, g, and b in the set [0, 255].
   *
   * @param {number} h The hue
   * @param {number} s The saturation
   * @param {number} v The value
   * @return {!Array.<number>} The RGB representation
   */
  var hsvToRgb = function(h, s, v) {
    var r;
    var g;
    var b;

    var i = Math.floor(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);

    switch(i % 6) {
      case 0: r = v, g = t, b = p; break;
      case 1: r = q, g = v, b = p; break;
      case 2: r = p, g = v, b = t; break;
      case 3: r = p, g = q, b = v; break;
      case 4: r = t, g = p, b = v; break;
      case 5: r = v, g = p, b = q; break;
    }

    return [r * 255, g * 255, b * 255];
  };

  /**
   * Adjusts the hue, saturation and value of an image.
   * @param {!Image} image an Image tag
   * @param {number} hue The amount to adjust the hue.
   * @param {number} saturation The amount to adjust the
   *     saturation.
   * @param {number} value. The amount to adjust the value.
   *     image
   * @param {number} opt_hueRangeLimit. Defines a hue range,
   *        Pixels outside this range will not be adjusted. Note:
   *        the first value is the starting hue and the second
   *        the ending hue. So [0.1, 0.2] adjusts pixels with hues
   *        between 0.1<->0.2 where as [0.2,0.1] adjusts pixels
   *        with hues from 0.2<->1.0 and 0.0<->0.1. In other words
   *        only 0.1<->0.2 will not be adjusted.
   *
   *        What's the point? Let's say you have a character with
   *        blue shirt and a pink face. If you adjust all the
   *        colors the face would change from pink. If you select
   *        a range that covers only blue then only the blue
   *        pixels will be adjusted letting you adjust only the
   *        shirt.
   *
   *        To figure out the ranges use photoshop's
   *        hue/saturation layer. Near the top of the settings
   *        pick the drop down "Master", pick a color, the adjust
   *        the sliders. Photoshop gives the settings in degrees
   *        so you'll have to convert to 0 to 1 (eg,
   *        photoshopValue / 360)
   *
   * @return {!Canvas} a canvas element with the adjusted image.
   */
  var adjustHSV = function(image, hue, saturation, value, opt_hueRangeLimit) {
    opt_hueRangeLimit = opt_hueRangeLimit || [0, 1];
    var minHue = (opt_hueRangeLimit[0] + 0.0) % 1;
    var maxHue = (opt_hueRangeLimit[1] + 0.0) % 1;

    // |<------------>|
    //    min     max      min<->mz
    //
    //    max     min      min->1  0->max

    var minLessThanMax = function(v) {
      return v >= minHue && v <= maxHue;
    };

    var maxLessThanMin = function(v) {
      return v >= minHue || v <= maxHue;
    };

    var validHue = minHue < maxHue ? minLessThanMax : maxLessThanMin;
    var canvas = document.createElement("canvas");
    var width = image.width;
    var height = image.height;
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    var imageData = ctx.getImageData(0, 0, width, height);
    var pixels = imageData.data;
    var numPixels = width * height;
    var numBytes = numPixels * 4;
    for (var offset = 0; offset < numBytes; offset += 4) {
      var hsv = rgbToHsv(pixels[offset + 0], pixels[offset + 1], pixels[offset + 2]);
      if (!validHue(hsv[0])) {
        continue;
      }
      var h = (hsv[0] + hue + 100) % 1;
      var s = Math.min(1, Math.max(0, hsv[1] + saturation));
      var v = Math.min(1, Math.max(0, hsv[2] + value));
      var rgb = hsvToRgb(h, s, v);
      pixels[offset + 0] = rgb[0];
      pixels[offset + 1] = rgb[1];
      pixels[offset + 2] = rgb[2];
    }
    ctx.putImageData(imageData, 0, 0);
    return canvas;
  };

  // Returns a canvas with the cropped piece only.
  // @param {!Image|!Canvas} src image or canvas to crop
  // @param {number} x left
  // @param {number} y top
  // @param {number} width width
  // @param {number} height height
  var cropImage = function(src, x, y, width, height) {
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(src, x, y, width, height, 0, 0, width, height);
    return canvas;
  };

  // Returns a scaled canvas using nearest neighbor.
  // @param {!Image|!Canvas} src image or canvas to scale
  // @param {number} newWidth width
  // @param {number} newHeight height
  var scaleImage = function(src, newWidth, newHeight) {
    var canvas = document.createElement("canvas");
    canvas.width = src.width;
    canvas.height = src.height;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(src, 0, 0);
    var srcImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var srcPixels = srcImageData.data;
    canvas.width = newWidth;
    canvas.height = newHeight;
    var dstImageData = ctx.createImageData(newWidth, newHeight);
    var dstPixels = dstImageData.data;
    for (var y = 0; y < newHeight; ++y) {
      var srcY = (y * src.height / newHeight) | 0;
      var dstOffset = y * newWidth * 4;
      for (var x = 0; x < newWidth; ++x) {
        var srcX = (x * src.width / newWidth) | 0;
        var srcOffset = (srcY * src.width + srcX) * 4;
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
        dstPixels[dstOffset++] = srcPixels[srcOffset++];
      }
    }
    ctx.putImageData(dstImageData, 0, 0);
    return canvas;
  };

  var makeTextImage = function(str, options, opt_canvas) {
    var canvas = opt_canvas || document.createElement("canvas");
    var ctx = canvas.getContext("2d");

    ctx.save();

    if (options.font        ) { ctx.font         = options.font;        }
    if (options.fillStyle   ) { ctx.fillStyle    = options.fillStyle;   }
    if (options.textAlign   ) { ctx.textAlign    = options.textAlign;   }
    if (options.testBaseline) { ctx.textBaseline = options.textBaselne; }

    var metrics = ctx.measureText(str);
    var width = metrics.width + (options.padding || 0);
    if (options.maxWidth) {
      width = Math.min(width, options.maxWidth);
    }
    if (options.minWidth) {
      width = Math.max(width, options.minWidth);
    }
    canvas.width = width;
    canvas.height = options.height;

    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.fillText(
        str,
        options.xOffset || 0,
        options.yOffset || 0);

    ctx.restore();
    return canvas;
  };

  return {
    adjustHSV: adjustHSV,
    cropImage: cropImage,
    makeTextImage: makeTextImage,
    scaleImage: scaleImage,
  };
});
<|endoftext|>


<commit_before>transporter.module.create('projects/projects', function(requires) {}, function(thisModule) {

thisModule.addSlots(avocado, function(add) {

  add.creator('project', {}, {category: ['projects']});

});

thisModule.addSlots(avocado.project, function(add) {

  add.method('current', function () {
    return this._current || (this._current = this.create("This project"));
  }, {category: ['current one']});

  add.method('create', function (name) {
    return Object.newChildOf(this, name);
  }, {category: ['creating']});

  add.method('initialize', function (name) {
    this.setName(name);
    transporter.idTracker.createTemporaryIDFor(this);
  }, {category: ['creating']});

  add.method('name', function () { return this._name; }, {category: ['accessing']});

  add.method('setName', function (n) { this._name = n; }, {category: ['accessing']});

  add.method('id', function () { return this._projectID; }, {category: ['accessing']});

  add.method('setID', function (id) { this._projectID = id; }, {category: ['accessing']});

  add.method('module', function () { return modules.thisProject; }, {category: ['accessing']});

  add.method('inspect', function () { return this.name(); }, {category: ['printing']});

  add.method('save', function (evt) {
    var versionsToSave = {};
    var modulesNotToSave = {};
    var modulesLeftToLookAt = [this.module()];
    while (modulesLeftToLookAt.length > 0) {
      var m = modulesLeftToLookAt.pop();
      if (!modulesNotToSave[m.name()] && !versionsToSave[m.name()]) {
        // aaa - Could make this algorithm faster if each module knew who required him - just check
        // if m itself has changed, and if so then walk up the requirements chain making sure that
        // they're included.
        if (m.haveIOrAnyOfMyRequirementsChangedSinceLastFileOut()) {
          versionsToSave[m.name()] = m.createNewVersion();
          m.requirements().each(function(requiredModuleName) { modulesLeftToLookAt.push(modules[requiredModuleName])});
        } else {
          modulesNotToSave[m.name()] = m;
        }
      }
    }

    var moduleGraph = avocado.graphs.directed.create([this.module()], function(m) { return m.requiredModules(); });
    var sortedModules = moduleGraph.topologicalSort();
    var sortedVersionsToSave = [];
    sortedModules.each(function(m) {
      var v = versionsToSave[m.name()];
      if (v) { sortedVersionsToSave.push(v); }
    });

    var mockRepo = avocado.project.repository.create(this);
    mockRepo.setRoot(versionsToSave[this.module().name()]);
    var errors = transporter.fileOutPlural(sortedVersionsToSave.map(function(v) { return { moduleVersion: v }; }), evt, mockRepo, transporter.module.justBodyFilerOuter);
    if (errors.length === 0) {
      mockRepo.save(function() { console.log("Triumph!"); }, function(failureReason) { console.log("Aww, man: " + failureReason); });
    } else {
      console.log("Not saving because there were transporter errors.");
    }
  }, {category: ['saving']});

  add.creator('repository', {}, {category: ['saving']});

  add.method('buttonCommands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('Save', this.save)
    ]);
  }, {category: ['user interface', 'commands']});

});

thisModule.addSlots(avocado.project.repository, function(add) {

  add.method('create', function (project) {
    return Object.newChildOf(this, project);
  }, {category: ['creating']});

  add.method('initialize', function (project) {
    this._project = project;
    this._projectData = { _id: project.id(), name: project.name(), modules: [] };
  }, {category: ['creating']});

  add.method('setRoot', function (rootModuleVersion) {
    this._projectData.root = rootModuleVersion.versionID();
  }, {category: ['saving']});

  add.method('fileOutModuleVersion', function (moduleVersion, codeToFileOut, successBlock, failBlock) {
    this._projectData.modules.push({
      module: moduleVersion.module().name(),
      version: moduleVersion.versionID(),
      parents: moduleVersion.parentVersions().map(function(pv) { return pv.versionID(); }),
      reqs: moduleVersion.requiredModuleVersions().map(function(v) { return v.versionID(); }),
      code: codeToFileOut
    });
  }, {category: ['saving']});

  add.method('save', function (successBlock, failBlock) {
    var json = Object.toJSON(this._projectData);
    // aaa - I imagine it's possible to send the JSON without encoding it as a POST parameter, but let's not worry about it yet.
    var postBody = "projectDataJSON=" + encodeURIComponent(json);
    var url = "http://localhost:3000/project/save"; // aaa don't hard-code this
    console.log("About to save the project to URL " + url + ", sending JSON:\n" + json);
    var req = new Ajax.Request(url, {
      method: 'post',
      //postBody: postBody,
      //contentType: 'application/x-www-form-urlencoded',
      postBody: json,
      contentType: 'application/json',

      asynchronous: true,
      onSuccess:   function(transport) { this.onSuccessfulSave(transport.responseText, successBlock, failBlock); }.bind(this),
      onFailure:   function(t        ) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; HTTP status code was " + req.getStatus()); }.bind(this),
      onException: function(r,      e) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; exception was " + e); }.bind(this)
    });
  }, {category: ['saving']});

  add.method('onSuccessfulSave', function (responseText, successBlock, failBlock) {
    var realIDsByTempID = JSON.parse(responseText);
    for (var tempID in realIDsByTempID) {
      transporter.idTracker.recordRealID(tempID, realIDsByTempID[tempID]);
    }
    successBlock();
  }, {category: ['saving']});

});

});
<commit_msg>Let a project be marked as private (though there's still no UI for it).<commit_after>transporter.module.create('projects/projects', function(requires) {}, function(thisModule) {

thisModule.addSlots(avocado, function(add) {

  add.creator('project', {}, {category: ['projects']});

});

thisModule.addSlots(avocado.project, function(add) {

  add.method('current', function () {
    return this._current || (this._current = this.create({ name: "This project" }));
  }, {category: ['current one']});

  add.method('setCurrent', function (p) {
    this._current = p;
  }, {category: ['current one']});

  add.method('create', function (info) {
    return Object.newChildOf(this, info);
  }, {category: ['creating']});

  add.method('initialize', function (info) {
    this.setName(info.name);
    this.setIsPrivate(info.isPrivate);
    if (info._id) {
      this.setID(info._id);
    } else {
      transporter.idTracker.createTemporaryIDFor(this);
    }
  }, {category: ['creating']});

  add.method('name', function () { return this._name; }, {category: ['accessing']});

  add.method('setName', function (n) { this._name = n; }, {category: ['accessing']});

  add.method('id', function () { return this._projectID; }, {category: ['accessing']});

  add.method('setID', function (id) { this._projectID = id; }, {category: ['accessing']});

  add.method('isPrivate', function () { return this._isPrivate; }, {category: ['accessing']});

  add.method('setIsPrivate', function (b) { this._isPrivate = b; }, {category: ['accessing']});

  add.method('module', function () { return modules.thisProject; }, {category: ['accessing']});

  add.method('inspect', function () { return this.name(); }, {category: ['printing']});

  add.method('save', function (evt) {
    var versionsToSave = {};
    var modulesNotToSave = {};
    var modulesLeftToLookAt = [this.module()];
    while (modulesLeftToLookAt.length > 0) {
      var m = modulesLeftToLookAt.pop();
      if (!modulesNotToSave[m.name()] && !versionsToSave[m.name()]) {
        // aaa - Could make this algorithm faster if each module knew who required him - just check
        // if m itself has changed, and if so then walk up the requirements chain making sure that
        // they're included.
        if (m.haveIOrAnyOfMyRequirementsChangedSinceLastFileOut()) {
          versionsToSave[m.name()] = m.createNewVersion();
          m.requirements().each(function(requiredModuleName) { modulesLeftToLookAt.push(modules[requiredModuleName])});
        } else {
          modulesNotToSave[m.name()] = m;
        }
      }
    }

    var moduleGraph = avocado.graphs.directed.create([this.module()], function(m) { return m.requiredModules(); });
    var sortedModules = moduleGraph.topologicalSort();
    var sortedVersionsToSave = [];
    sortedModules.each(function(m) {
      var v = versionsToSave[m.name()];
      if (v) { sortedVersionsToSave.push(v); }
    });

    var mockRepo = avocado.project.repository.create(this);
    mockRepo.setRoot(versionsToSave[this.module().name()]);
    var errors = transporter.fileOutPlural(sortedVersionsToSave.map(function(v) { return { moduleVersion: v }; }), evt, mockRepo, transporter.module.justBodyFilerOuter);
    if (errors.length === 0) {
      mockRepo.save(function() { console.log("Triumph!"); }, function(failureReason) { console.log("Aww, man: " + failureReason); });
    } else {
      console.log("Not saving because there were transporter errors.");
    }
  }, {category: ['saving']});

  add.creator('repository', {}, {category: ['saving']});

  add.method('buttonCommands', function () {
    return avocado.command.list.create(this, [
      avocado.command.create('Save', this.save)
    ]);
  }, {category: ['user interface', 'commands']});

});

thisModule.addSlots(avocado.project.repository, function(add) {

  add.method('create', function (project) {
    return Object.newChildOf(this, project);
  }, {category: ['creating']});

  add.method('initialize', function (project) {
    this._project = project;
    this._projectData = { _id: project.id(), name: project.name(), isPrivate: project.isPrivate(), modules: [] };
  }, {category: ['creating']});

  add.method('setRoot', function (rootModuleVersion) {
    this._projectData.root = rootModuleVersion.versionID();
  }, {category: ['saving']});

  add.method('fileOutModuleVersion', function (moduleVersion, codeToFileOut, successBlock, failBlock) {
    this._projectData.modules.push({
      module: moduleVersion.module().name(),
      version: moduleVersion.versionID(),
      parents: moduleVersion.parentVersions().map(function(pv) { return pv.versionID(); }),
      reqs: moduleVersion.requiredModuleVersions().map(function(v) { return v.versionID(); }),
      code: codeToFileOut
    });
  }, {category: ['saving']});

  add.method('save', function (successBlock, failBlock) {
    var json = Object.toJSON(this._projectData);
    // aaa - I imagine it's possible to send the JSON without encoding it as a POST parameter, but let's not worry about it yet.
    var postBody = "projectDataJSON=" + encodeURIComponent(json);
    var url = "http://localhost:3000/project/save"; // aaa don't hard-code this
    console.log("About to save the project to URL " + url + ", sending JSON:\n" + json);
    var req = new Ajax.Request(url, {
      method: 'post',
      //postBody: postBody,
      //contentType: 'application/x-www-form-urlencoded',
      postBody: json,
      contentType: 'application/json',

      asynchronous: true,
      onSuccess:   function(transport) { this.onSuccessfulSave(transport.responseText, successBlock, failBlock); }.bind(this),
      onFailure:   function(t        ) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; HTTP status code was " + req.getStatus()); }.bind(this),
      onException: function(r,      e) { failBlock("Failed to file out project " + this._project + " to repository " + this + "; exception was " + e); }.bind(this)
    });
  }, {category: ['saving']});

  add.method('onSuccessfulSave', function (responseText, successBlock, failBlock) {
    var realIDsByTempID = JSON.parse(responseText);
    for (var tempID in realIDsByTempID) {
      transporter.idTracker.recordRealID(tempID, realIDsByTempID[tempID]);
    }
    successBlock();
  }, {category: ['saving']});

});

});
<|endoftext|>


<commit_before>// boot jQuery
var $j = jQuery.noConflict();

// add load event
Event.observe(window, 'load', init_load_wym_editor, false);

// These tokens are for Radiant CMS radius tags
XhtmlLexer.prototype.addTokens = function()
{
  this.addEntryPattern("</?r:", 'Text', 'Text');
  this.addExitPattern(">", 'Text');

  this.addCommentTokens('Text');
  this.addScriptTokens('Text');
  this.addCssTokens('Text');
  this.addTagTokens('Text');
}

function text_input_method(index, filter) {
	if (index != null) {
		// control for page parts
		var elem = $('part['+(index - 1)+'][content]');
		if (filter == "WymEditor") {
			boot_wym(elem);
		} else {
			for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
			unboot_wym(elem)
		}
	} else {
		// control for snippets
		var elem = $$('.textarea');
		if (filter == "WymEditor") {
			boot_wym(elem[0]);
		} else {
			for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
			unboot_wym(elem[0]);
		}
	}
}

// loads WYMeditor for page parts where "WymEditor" is the selected text filter
function init_load_wym_editor(){
	// add "wymupdate" class to the save buttons:
	for (var i = 0; i < $$(".button").length; i++){
		//$($$(".button")[i]).addClassName('wymupdate');
		// on save, run wymupdate and unboot on all instances;
		Event.observe($$(".button")[i], 'click', unboot_all_wym)
	}

  // check to see if we are working with a page or with a snippet
  if ($('part[0][filter_id]'))
  {
    var parts = $j('.textarea');
    for (var i = 0; i < parts.length; i++)
    {
      if ($F('part[' + i + '][filter_id]') == 'WymEditor') {
				// mark textarea's that need to be wymified
				$('part['+i+'][content]').addClassName('wymified');
      }
    }
		// boot wym on marked textarea's
		ta = $$(".wymified");
		for (var i = 0; i < ta.length; i++){
			boot_wym(ta[i]);
		}

  } else if ($('snippet[filter_id]')) {
    if ($F('snippet[filter_id]') == 'WymEditor') {
			boot_wym($j('.textarea')[0]);
    }
  }
}

function boot_wym(elem){
   $j(elem).wymeditor({
				xhtmlParser: 'xhtml_parser.js',
			  cssParser:   'wym_css_parser.js',

 			 //classes panel
	      classesItems: [
	        {'name': 'float-left', 'title': 'PARA: left', 'expr': 'p'},
	        {'name': 'float-right', 'title': 'PARA: right', 'expr': 'p'}
	      ],

	      //editor css values for visual feedback
	      editorStyles: [
	        {'name': '.float-left',
	         'css': 'color: #999; border: 2px solid #ccc;'},
	        {'name': '.float-right',
	          'css': 'color: #999; border: 2px solid #ccc;'},
					{'name': '.radius_tag',
						'css': 'height:31px; background:url(/images/admin/wef_radiustag_bg.gif) no-repeat 0 0;'}
	      ],

      //function called when WYMeditor instance is ready
      //wym is the WYMeditor instance
      postInit: function(wym) {
        //set the status bar value
        wym.status(' ');
        //activate 'hovertools' plugin, which gives more feedback to the user
        wym.hovertools();
      },

			preInit: function(wym) {
				//change_radius_to_imgs
				var content = (wym._html);
				var m = content.match(/(<r:([^\/><]*)?\/?>)|(<\/r:([^>]*)?>)/g);
				if (!(m == null)) {
					for (var i=0; i < m.length; i++) {
				  	var title = m[i].replace(/"/g, "'");
						title = title.substring(1,title.length-1);
				    var match = escape(m[i].substring(1,m[i].length - 1));
				    var regex = new RegExp('(' + m[i] + ')', 'i');
				    var content = content.replace(regex, '');
					}
				}
				wym._html = content;
			}
   });
}

function unboot_wym(elem){
	// hide wym
	$j(elem).parent().find(".wym_box").remove();
	// revert images to radius tags
	var content = elem.value;
	var regex = new RegExp('', 'gi');
	var m = content.match(regex);
	   if (!(m == null)) {
	       for (var i=0; i<m.length; i++) {
	           var match = unescape(m[i].replace(regex, '<$1>'));
	           var content = content.replace(m[i], match);
	       }
	   }
	elem.value = content
	// show textarea again
  $j(elem).show();
}

function unboot_all_wym() {
	// wym.update() for all!
	for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
	var ta = $$('.textarea');
	for(var i = 0; i < ta.length; i++){
		unboot_wym(ta[i]);
	}
	return true;
}<commit_msg>updating radius visualisation<commit_after>// boot jQuery
var $j = jQuery.noConflict();

// add load event
Event.observe(window, 'load', init_load_wym_editor, false);

// These tokens are for Radiant CMS radius tags
XhtmlLexer.prototype.addTokens = function()
{
  this.addEntryPattern("</?r:", 'Text', 'Text');
  this.addExitPattern(">", 'Text');

  this.addCommentTokens('Text');
  this.addScriptTokens('Text');
  this.addCssTokens('Text');
  this.addTagTokens('Text');
}

function text_input_method(index, filter) {
	if (index != null) {
		// control for page parts
		var elem = $('part['+(index - 1)+'][content]');
		if (filter == "WymEditor") {
			boot_wym(elem);
		} else {
			for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
			unboot_wym(elem)
		}
	} else {
		// control for snippets
		var elem = $$('.textarea');
		if (filter == "WymEditor") {
			boot_wym(elem[0]);
		} else {
			for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
			unboot_wym(elem[0]);
		}
	}
}

// loads WYMeditor for page parts where "WymEditor" is the selected text filter
function init_load_wym_editor(){
	// add "wymupdate" class to the save buttons:
	for (var i = 0; i < $$(".button").length; i++){
		//$($$(".button")[i]).addClassName('wymupdate');
		// on save, run wymupdate and unboot on all instances;
		Event.observe($$(".button")[i], 'click', unboot_all_wym)
	}

  // check to see if we are working with a page or with a snippet
  if ($('part[0][filter_id]'))
  {
    var parts = $j('.textarea');
    for (var i = 0; i < parts.length; i++)
    {
      if ($F('part[' + i + '][filter_id]') == 'WymEditor') {
				// mark textarea's that need to be wymified
				$('part['+i+'][content]').addClassName('wymified');
      }
    }
		// boot wym on marked textarea's
		ta = $$(".wymified");
		for (var i = 0; i < ta.length; i++){
			boot_wym(ta[i]);
		}

  } else if ($('snippet[filter_id]')) {
    if ($F('snippet[filter_id]') == 'WymEditor') {
			boot_wym($j('.textarea')[0]);
    }
  }
}

function boot_wym(elem){
   $j(elem).wymeditor({
				xhtmlParser: 'xhtml_parser.js',
			  cssParser:   'wym_css_parser.js',

 			 //classes panel
	      classesItems: [
	        {'name': 'float-left', 'title': 'PARA: left', 'expr': 'p'},
	        {'name': 'float-right', 'title': 'PARA: right', 'expr': 'p'}
	      ],

	      //editor css values for visual feedback
	      editorStyles: [
	        {'name': '.float-left',
	         'css': 'color: #999; border: 2px solid #ccc;'},
	         {'name': '.float-right',
	          'css': 'color: #999; border: 2px solid #ccc;'},
					{'name': '.radius_tag',
						'css': 'height:31px; background:url(/images/admin/wef_radiustag_bg.gif) no-repeat 0 0;'},
						// Make div element stand out visually, add label
  				{'name': 'div',
  					'css': 'background:#fafceb url(/images/admin/lbl-div.png) no-repeat 2px 2px; margin:10px; padding:10px;'}
	      ],

      //function called when WYMeditor instance is ready
      //wym is the WYMeditor instance
      postInit: function(wym) {
        //set the status bar value
        wym.status(' ');
        //activate 'hovertools' plugin, which gives more feedback to the user
        wym.hovertools();
      },

			preInit: function(wym) {
				//change_radius_to_imgs
				var content = (wym._html);
				var m = content.match(/(<r:([^\/><]*)?\/?>)|(<\/r:([^>]*)?>)/g);
				if (!(m == null)) {
					for (var i=0; i < m.length; i++) {
				  	var title = m[i].replace(/"/g, "'");
						title = title.substring(1,title.length-1);
				    var match = escape(m[i].substring(1,m[i].length - 1));
				    var regex = new RegExp('(' + m[i] + ')', 'i');
				    var content = content.replace(regex, '
');
					}
				}
				wym._html = content;
			}
   });
}

function unboot_wym(elem){
	// hide wym
	$j(elem).parent().find(".wym_box").remove();
	// revert images to radius tags
	var content = elem.value;
	var regex = new RegExp('
', 'gi');
	var m = content.match(regex);
	   if (!(m == null)) {
	       for (var i=0; i<m.length; i++) {
	           var match = unescape(m[i].replace(regex, '<$1>'));
	           var content = content.replace(m[i], match);
	       }
	   }
	elem.value = content
	// show textarea again
  $j(elem).show();
}

function unboot_all_wym() {
	// wym.update() for all!
	for(var i=0;i<WYM_INSTANCES.length;i++) { WYM_INSTANCES[i].update(); };
	var ta = $$('.textarea');
	for(var i = 0; i < ta.length; i++){
		unboot_wym(ta[i]);
	}
	return true;
}<|endoftext|>