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

const exec = require("child_process").execSync;

const generator = require("./generator");
const fu = require("./futil");

const dirs = [
  // Flux
  "./app",
  "./app/actions",
  "./app/constants",
  "./app/components",
  "./app/dispatcher",
  "./app/stores",
  "./app/utils",

  // Build
  "./public",
  "./public/css",
  "./public/img",
  "./public/js",

  // Jest
  "./__tests__"
];

const npms = [
  // Babel
  "yarn add --dev @babel/cli",
  "yarn add --dev @babel/core",
  "yarn add --dev @babel/preset-env",
  "yarn add --dev @babel/preset-react",

  // Stage 0
  "yarn add --dev @babel/plugin-proposal-function-bind",

  // Stage 1
  "yarn add --dev @babel/plugin-proposal-export-default-from",
  "yarn add --dev @babel/plugin-proposal-logical-assignment-operators",
  "yarn add --dev @babel/plugin-proposal-optional-chaining",
  "yarn add --dev @babel/plugin-proposal-pipeline-operator",
  "yarn add --dev @babel/plugin-proposal-nullish-coalescing-operator",
  "yarn add --dev @babel/plugin-proposal-do-expressions",

  // Stage 2
  "yarn add --dev @babel/plugin-proposal-decorators",
  "yarn add --dev @babel/plugin-proposal-function-sent",
  "yarn add --dev @babel/plugin-proposal-export-namespace-from",
  "yarn add --dev @babel/plugin-proposal-numeric-separator",
  "yarn add --dev @babel/plugin-proposal-throw-expressions",

  // Stage 3
  "yarn add --dev @babel/plugin-syntax-dynamic-import",
  "yarn add --dev @babel/plugin-syntax-import-meta",
  "yarn add --dev @babel/plugin-proposal-class-properties",
  "yarn add --dev @babel/plugin-proposal-json-strings",

  "yarn add --dev @babel/plugin-transform-runtime",

  // React.js
  "yarn add react",
  "yarn add react-dom",
  "yarn add prop-types",
  //  "yarn add --dev raf",

  // Flux
  "yarn add flux",

  // Immutable.js
  "yarn add immutable",

  // Jest
  "yarn add --dev jest-cli",
  "yarn add --dev babel-jest",
  "yarn add --dev babel-core@^7.0.0-0",
  "yarn add --dev regenerator-runtime",

  // WebPack
  "yarn add --dev webpack",
  "yarn add --dev webpack-cli",
  "yarn add --dev webpack-dev-server",
  "yarn add --dev webpack-bundle-analyzer",
  "yarn add --dev babel-loader",

  // ESLint
  "yarn add --dev eslint",
  "yarn add --dev babel-eslint",
  "yarn add --dev eslint-plugin-import",
  "yarn add --dev eslint-plugin-react",
  "yarn add --dev eslint-plugin-jsx-a11y",
  "yarn add --dev eslint-config-airbnb",

  // Prettier
  "yarn add --dev prettier",
  "yarn add --dev eslint-plugin-prettier",
  "yarn add --dev eslint-config-prettier"
];

const npms_plus = [
  "yarn add @material-ui/core",
  "yarn add @material-ui/icons",
  "yarn add react-router-dom",
  "yarn add axios"
];

const repository = {
  type: "git",
  url: "https://example.com"
};

const jest = {
  unmockedModulePathPatterns: [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils"
  ],
  transform: {
    "^.+\\.jsx?$": "babel-jest"
  },
  moduleFileExtensions: ["js", "json"]
};

const scripts = {
  start: "webpack-dev-server --progress --colors --mode development",
  dev: "webpack -p --progress --colors --mode development",
  build: "webpack -p --progress --colors --mode production",
  test: "jest",
  lint: "eslint app/** __tests__/**",
  fix: "eslint app/** __tests__/** --fix",
  "bundle-analyze":
    "webpack --profile --json > stats.json && webpack-bundle-analyzer ./stats.json"
};

const eslint = {
  extends: ["airbnb", "prettier", "prettier/react"],
  parser: "babel-eslint",
  env: {
    browser: true,
    jest: true
  },
  plugins: ["prettier"],
  rules: {
    "react/jsx-filename-extension": [1, { extensions: [".js"] }],
    "react/no-find-dom-node": 0,
    "jsx-a11y/anchor-is-valid": [
      "error",
      {
        components: ["Link"],
        specialLink: ["to", "hrefLeft", "hrefRight"],
        aspects: ["noHref", "invalidHref", "preferButton"]
      }
    ]
  }
};

const keywords = {
  keywords: ["react", "flux"]
};

main();

function main() {
  console.log("*** starter-react-flux ***");
  const args = process.argv;
  switch (args.length) {
    case 3:
      if (args[2] == "init") {
        setupReact();
        setupReactPlus();
        showComplete();
      } else if (args[2] == "init-basic") {
        setupReact();
        showUsage();
      }
      break;
    case 4:
      if (args[2] == "generate" && args[3] == "test") {
        generator.ComponentTestFiles();
        showComplete();
      } else {
        showUsage();
      }
      break;
    case 5:
      if (args[2] == "generate" && args[3] == "store") {
        generator.StoreFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "action") {
        generator.ActionFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "container") {
        generator.ContainerFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "component") {
        generator.ComponentFile(args[4]);
        showComplete();
      } else {
        showUsage();
      }
      break;
    default:
      showUsage();
      break;
  }
}

function showUsage() {
  console.log("*** starter-react-flux ***");
  console.log("Usage:");
  console.log(
    "starter-react-flux init                      : Setup a React/Flux project."
  );
  console.log(
    "starter-react-flux generate container [Name] : Generate the Component."
  );
  console.log(
    "starter-react-flux generate component [Name] : Generate the Container."
  );
  console.log(
    "starter-react-flux generate store  [Name]    : Generate the Store. "
  );
  console.log(
    "starter-react-flux generate action [Name]    : Generate the ActionCreators."
  );
  console.log(
    "starter-react-flux generate test             : Generate tests of components."
  );
  process.exit(-1);
}

function showComplete() {
  console.log("Completed!");
}

function setupReact(arg) {
  fu.createDirectories(dirs);
  exec("npm init -y", fu.puts);
  fu.fixJSON("package.json", "description", "React template.");
  fu.fixJSON("package.json", "repository", repository);
  fu.fixJSON("package.json", "jest", jest);
  fu.fixJSON("package.json", "scripts", scripts);
  fu.fixJSON("package.json", "keywords", keywords);
  fu.fixJSON("package.json", "license", "MIT");

  fu.createJSON(".eslintrc", eslint);
  fu.createJSON(".babelrc", {
    presets: ["@babel/preset-react", "@babel/preset-env"],
    plugins: [
      "@babel/plugin-transform-runtime",
      "@babel/plugin-proposal-function-bind",
      "@babel/plugin-proposal-export-default-from",
      "@babel/plugin-proposal-logical-assignment-operators",
      ["@babel/plugin-proposal-optional-chaining", { loose: false }],
      ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }],
      ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }],
      "@babel/plugin-proposal-do-expressions",
      ["@babel/plugin-proposal-decorators", { legacy: true }],
      "@babel/plugin-proposal-function-sent",
      "@babel/plugin-proposal-export-namespace-from",
      "@babel/plugin-proposal-numeric-separator",
      "@babel/plugin-proposal-throw-expressions",
      "@babel/plugin-syntax-dynamic-import",
      "@babel/plugin-syntax-import-meta",
      ["@babel/plugin-proposal-class-properties", { loose: false }],
      "@babel/plugin-proposal-json-strings"
    ]
  });
  console.log(__dirname);
  fu.createFile("./public/index.html", fu.readFile("./public/index.html"));
  fu.createFile("./public/css/style.css", fu.readFile("./public/main.css"));
  fu.createFile("webpack.config.js", fu.readFile("./app/webpack.js"));
  fu.createFile("./app/App.js", fu.readFile("./app/App.js"));
  fu.createFile(
    "./app/dispatcher/AppDispatcher.js",
    fu.readFile("./app/dispatcher/dispatcher.js")
  );
  fu.createFile(
    "./app/constants/AppConstants.js",
    fu.readFile("./app/constants/constant.js")
  );
  fu.createFile(
    "./app/components/Navi.js",
    fu.readFile("./app/components/Navi.js")
  );
  fu.createFile(
    "./app/components/Menu.js",
    fu.readFile("./app/components/Menu.js")
  );
  fu.createFile(
    "./app/components/Content.js",
    fu.readFile("./app/components/Content.js")
  );
  fu.createFile(
    "./__tests__/Content-test.js",
    fu.readFile("./__tests__/Content-test.js")
  );

  generator.StoreFile("Sample");
  generator.ActionFile("Sample");
  generator.ContainerFile("Top");
  generator.ContainerFile("Sample");
  npmInstall(npms);
}

function setupReactPlus() {
  npmInstall(npms_plus);
}

function npmInstall(npms) {
  npms.map(command => {
    console.log(command);
    exec(command, fu.puts);
  });
}
<commit_msg>use next tag of React<commit_after>#!/usr/bin/env node

const exec = require("child_process").execSync;

const generator = require("./generator");
const fu = require("./futil");

const dirs = [
  // Flux
  "./app",
  "./app/actions",
  "./app/constants",
  "./app/components",
  "./app/dispatcher",
  "./app/stores",
  "./app/utils",

  // Build
  "./public",
  "./public/css",
  "./public/img",
  "./public/js",

  // Jest
  "./__tests__"
];

const npms = [
  // Babel
  "yarn add --dev @babel/cli",
  "yarn add --dev @babel/core",
  "yarn add --dev @babel/preset-env",
  "yarn add --dev @babel/preset-react",

  // Stage 0
  "yarn add --dev @babel/plugin-proposal-function-bind",

  // Stage 1
  "yarn add --dev @babel/plugin-proposal-export-default-from",
  "yarn add --dev @babel/plugin-proposal-logical-assignment-operators",
  "yarn add --dev @babel/plugin-proposal-optional-chaining",
  "yarn add --dev @babel/plugin-proposal-pipeline-operator",
  "yarn add --dev @babel/plugin-proposal-nullish-coalescing-operator",
  "yarn add --dev @babel/plugin-proposal-do-expressions",

  // Stage 2
  "yarn add --dev @babel/plugin-proposal-decorators",
  "yarn add --dev @babel/plugin-proposal-function-sent",
  "yarn add --dev @babel/plugin-proposal-export-namespace-from",
  "yarn add --dev @babel/plugin-proposal-numeric-separator",
  "yarn add --dev @babel/plugin-proposal-throw-expressions",

  // Stage 3
  "yarn add --dev @babel/plugin-syntax-dynamic-import",
  "yarn add --dev @babel/plugin-syntax-import-meta",
  "yarn add --dev @babel/plugin-proposal-class-properties",
  "yarn add --dev @babel/plugin-proposal-json-strings",

  "yarn add --dev @babel/plugin-transform-runtime",

  // React.js
  "yarn add react@next",
  "yarn add react-dom@next",
  "yarn add prop-types@next",

  // Flux
  "yarn add flux",

  // Immutable.js
  "yarn add immutable",

  // Jest
  "yarn add --dev jest-cli",
  "yarn add --dev babel-jest",
  "yarn add --dev babel-core@^7.0.0-0",
  "yarn add --dev regenerator-runtime",

  // WebPack
  "yarn add --dev webpack",
  "yarn add --dev webpack-cli",
  "yarn add --dev webpack-dev-server",
  "yarn add --dev webpack-bundle-analyzer",
  "yarn add --dev babel-loader",

  // ESLint
  "yarn add --dev eslint",
  "yarn add --dev babel-eslint",
  "yarn add --dev eslint-plugin-import",
  "yarn add --dev eslint-plugin-react",
  "yarn add --dev eslint-plugin-jsx-a11y",
  "yarn add --dev eslint-config-airbnb",

  // Prettier
  "yarn add --dev prettier",
  "yarn add --dev eslint-plugin-prettier",
  "yarn add --dev eslint-config-prettier"
];

const npms_plus = [
  "yarn add @material-ui/core",
  "yarn add @material-ui/icons",
  "yarn add react-router-dom",
  "yarn add axios"
];

const repository = {
  type: "git",
  url: "https://example.com"
};

const jest = {
  unmockedModulePathPatterns: [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils"
  ],
  transform: {
    "^.+\\.jsx?$": "babel-jest"
  },
  moduleFileExtensions: ["js", "json"]
};

const scripts = {
  start: "webpack-dev-server --progress --colors --mode development",
  dev: "webpack -p --progress --colors --mode development",
  build: "webpack -p --progress --colors --mode production",
  test: "jest",
  lint: "eslint app/** __tests__/**",
  fix: "eslint app/** __tests__/** --fix",
  "bundle-analyze":
    "webpack --profile --json > stats.json && webpack-bundle-analyzer ./stats.json"
};

const eslint = {
  extends: ["airbnb", "prettier", "prettier/react"],
  parser: "babel-eslint",
  env: {
    browser: true,
    jest: true
  },
  plugins: ["prettier"],
  rules: {
    "react/jsx-filename-extension": [1, { extensions: [".js"] }],
    "react/no-find-dom-node": 0,
    "jsx-a11y/anchor-is-valid": [
      "error",
      {
        components: ["Link"],
        specialLink: ["to", "hrefLeft", "hrefRight"],
        aspects: ["noHref", "invalidHref", "preferButton"]
      }
    ]
  }
};

const keywords = {
  keywords: ["react", "flux"]
};

main();

function main() {
  console.log("*** starter-react-flux ***");
  const args = process.argv;
  switch (args.length) {
    case 3:
      if (args[2] == "init") {
        setupReact();
        setupReactPlus();
        showComplete();
      } else if (args[2] == "init-basic") {
        setupReact();
        showUsage();
      }
      break;
    case 4:
      if (args[2] == "generate" && args[3] == "test") {
        generator.ComponentTestFiles();
        showComplete();
      } else {
        showUsage();
      }
      break;
    case 5:
      if (args[2] == "generate" && args[3] == "store") {
        generator.StoreFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "action") {
        generator.ActionFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "container") {
        generator.ContainerFile(args[4]);
        showComplete();
      } else if (args[2] == "generate" && args[3] == "component") {
        generator.ComponentFile(args[4]);
        showComplete();
      } else {
        showUsage();
      }
      break;
    default:
      showUsage();
      break;
  }
}

function showUsage() {
  console.log("*** starter-react-flux ***");
  console.log("Usage:");
  console.log(
    "starter-react-flux init                      : Setup a React/Flux project."
  );
  console.log(
    "starter-react-flux generate container [Name] : Generate the Component."
  );
  console.log(
    "starter-react-flux generate component [Name] : Generate the Container."
  );
  console.log(
    "starter-react-flux generate store  [Name]    : Generate the Store. "
  );
  console.log(
    "starter-react-flux generate action [Name]    : Generate the ActionCreators."
  );
  console.log(
    "starter-react-flux generate test             : Generate tests of components."
  );
  process.exit(-1);
}

function showComplete() {
  console.log("Completed!");
}

function setupReact(arg) {
  fu.createDirectories(dirs);
  exec("npm init -y", fu.puts);
  fu.fixJSON("package.json", "description", "React template.");
  fu.fixJSON("package.json", "repository", repository);
  fu.fixJSON("package.json", "jest", jest);
  fu.fixJSON("package.json", "scripts", scripts);
  fu.fixJSON("package.json", "keywords", keywords);
  fu.fixJSON("package.json", "license", "MIT");

  fu.createJSON(".eslintrc", eslint);
  fu.createJSON(".babelrc", {
    presets: ["@babel/preset-react", "@babel/preset-env"],
    plugins: [
      "@babel/plugin-transform-runtime",
      "@babel/plugin-proposal-function-bind",
      "@babel/plugin-proposal-export-default-from",
      "@babel/plugin-proposal-logical-assignment-operators",
      ["@babel/plugin-proposal-optional-chaining", { loose: false }],
      ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }],
      ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }],
      "@babel/plugin-proposal-do-expressions",
      ["@babel/plugin-proposal-decorators", { legacy: true }],
      "@babel/plugin-proposal-function-sent",
      "@babel/plugin-proposal-export-namespace-from",
      "@babel/plugin-proposal-numeric-separator",
      "@babel/plugin-proposal-throw-expressions",
      "@babel/plugin-syntax-dynamic-import",
      "@babel/plugin-syntax-import-meta",
      ["@babel/plugin-proposal-class-properties", { loose: false }],
      "@babel/plugin-proposal-json-strings"
    ]
  });
  console.log(__dirname);
  fu.createFile("./public/index.html", fu.readFile("./public/index.html"));
  fu.createFile("./public/css/style.css", fu.readFile("./public/main.css"));
  fu.createFile("webpack.config.js", fu.readFile("./app/webpack.js"));
  fu.createFile("./app/App.js", fu.readFile("./app/App.js"));
  fu.createFile(
    "./app/dispatcher/AppDispatcher.js",
    fu.readFile("./app/dispatcher/dispatcher.js")
  );
  fu.createFile(
    "./app/constants/AppConstants.js",
    fu.readFile("./app/constants/constant.js")
  );
  fu.createFile(
    "./app/components/Navi.js",
    fu.readFile("./app/components/Navi.js")
  );
  fu.createFile(
    "./app/components/Menu.js",
    fu.readFile("./app/components/Menu.js")
  );
  fu.createFile(
    "./app/components/Content.js",
    fu.readFile("./app/components/Content.js")
  );
  fu.createFile(
    "./__tests__/Content-test.js",
    fu.readFile("./__tests__/Content-test.js")
  );

  generator.StoreFile("Sample");
  generator.ActionFile("Sample");
  generator.ContainerFile("Top");
  generator.ContainerFile("Sample");
  npmInstall(npms);
}

function setupReactPlus() {
  npmInstall(npms_plus);
}

function npmInstall(npms) {
  npms.map(command => {
    console.log(command);
    exec(command, fu.puts);
  });
}
<|endoftext|>


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

'use strict'

const fetchTimeline = require('fetch-timeline')
const formatDate = require('date-fns/format')
const multi = require('multi-write-stream')
const JSONStream = require('JSONStream')
const dateTime = require('date-time')
const prettyMs = require('pretty-ms')
const omit = require('lodash.omit')
const pick = require('lodash.pick')
const get = require('lodash.get')
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')

const pkg = require('../package.json')
require('update-notifier')({pkg}).notify()

const cli = require('meow')({
  pkg,
  help: fs.readFileSync(path.resolve(__dirname, 'help.txt'), 'utf8')
})

const getIdentifier = params => params.screenName || params.userId
const isString = str => typeof str === 'string'

const fileDate = () => formatDate(Date.now(), 'YYYY-MM-DD')

const CREDENTIALS = [
  'TWITTER_CONSUMER_KEY',
  'TWITTER_CONSUMER_SECRET',
  'TWITTER_ACCESS_TOKEN',
  'TWITTER_ACCESS_TOKEN_SECRET'
]

const lineBreak = () => process.stdout.write('\n')

const log = require('acho').skin(require('acho-skin-cli'))({
  align: false,
  keyword: 'symbol'
})

function exitOnError (err, code) {
  const collection = [].concat(err)
  collection.forEach(err => log.error(err.message || err))
  process.exit(code || 1)
}

function checkEnv (envs) {
  const errors = []
  envs.forEach(function (env) {
    if (!process.env[env]) {
      const message = `You need to provide '${env}'.`
      errors.push(new Error(message))
    }
  })

  if (errors.length > 0) return exitOnError(errors)
}

lineBreak()
checkEnv(CREDENTIALS)

const credentials = {
  consumerKey: process.env.TWITTER_CONSUMER_KEY,
  consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
  accessToken: process.env.TWITTER_ACCESS_TOKEN,
  accessTokenSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET
}

const {flags} = cli
const params = omit(flags, ['limit', 'save', 'limitDays'])
const opts = Object.assign(pick(flags, ['limit', 'limitDays']), {credentials})

const stream = fetchTimeline(params, opts)
const writables = [ process.stdout ]
const {save, showInfo} = flags
let endMessage

if (save) {
  const identifier = getIdentifier(params)
  const filename = isString(save)
    ? save
    : `${identifier}.${fileDate()}.json`

  endMessage = `Saved at '${filename}'.`
  writables.push(fs.createWriteStream(filename))
}

const writable = multi(writables)

stream
  .pipe(JSONStream.stringify('[', ',\n', ']\n', 2))
  .pipe(writable)

stream.on('error', function (err) {
  // TODO: Create a better error message with res headers:
  // X-Rate-Limit-Limit: the rate limit ceiling for that given request
  // X-Rate-Limit-Remaining: the number of requests left for the 15 minute window
  // X-Rate-Limit-Reset: the remaining window before the rate limit resets in UTC epoch seconds
  const {statusCode, message: errMessage, code} = err
  const message = `${statusCode}: ${errMessage}`
  exitOnError(message, code)
})

if (showInfo) {
  stream.on('info', function (info) {
    const {apiCalls, count, newerTweetDate, olderTweetDate} = info
    const screenName = get(info, 'user.screen_name')

    setTimeout(function () {
      lineBreak()
      log.info(`${chalk.white('Total API calls  :')} ${apiCalls} calls`)
      log.info(`${chalk.white('Total tweets     :')} ${count} tweets`)

      if (count) {
        const now = Date.now()
        const newer = dateTime(newerTweetDate)
        const older = dateTime(olderTweetDate)
        const newerAgo = prettyMs(now - newerTweetDate.getTime())
        const olderAgo = prettyMs(now - olderTweetDate.getTime())

        log.info(`${chalk.white('Newer tweet date :')} ${newer} (${newerAgo})`)
        log.info(`${chalk.white('Older tweet date :')} ${older} (${olderAgo})`)
      }

      if (screenName) {
        const twitterUrl = `https://twitter.com/${screenName}`
        log.info(`${chalk.white('User profile     :')} ${twitterUrl}`)
      }

      if (endMessage) {
        lineBreak()
        log.success(endMessage)
      }
    }, 250)
  })
}
<commit_msg>Prevent send show_info to twitter API<commit_after>#!/usr/bin/env node

'use strict'

const fetchTimeline = require('fetch-timeline')
const formatDate = require('date-fns/format')
const multi = require('multi-write-stream')
const JSONStream = require('JSONStream')
const dateTime = require('date-time')
const prettyMs = require('pretty-ms')
const omit = require('lodash.omit')
const pick = require('lodash.pick')
const get = require('lodash.get')
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')

const pkg = require('../package.json')
require('update-notifier')({pkg}).notify()

const cli = require('meow')({
  pkg,
  help: fs.readFileSync(path.resolve(__dirname, 'help.txt'), 'utf8')
})

const getIdentifier = params => params.screenName || params.userId
const isString = str => typeof str === 'string'

const fileDate = () => formatDate(Date.now(), 'YYYY-MM-DD')

const CREDENTIALS = [
  'TWITTER_CONSUMER_KEY',
  'TWITTER_CONSUMER_SECRET',
  'TWITTER_ACCESS_TOKEN',
  'TWITTER_ACCESS_TOKEN_SECRET'
]

const lineBreak = () => process.stdout.write('\n')

const log = require('acho').skin(require('acho-skin-cli'))({
  align: false,
  keyword: 'symbol'
})

function exitOnError (err, code) {
  const collection = [].concat(err)
  collection.forEach(err => log.error(err.message || err))
  process.exit(code || 1)
}

function checkEnv (envs) {
  const errors = []
  envs.forEach(function (env) {
    if (!process.env[env]) {
      const message = `You need to provide '${env}'.`
      errors.push(new Error(message))
    }
  })

  if (errors.length > 0) return exitOnError(errors)
}

lineBreak()
checkEnv(CREDENTIALS)

const credentials = {
  consumerKey: process.env.TWITTER_CONSUMER_KEY,
  consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
  accessToken: process.env.TWITTER_ACCESS_TOKEN,
  accessTokenSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET
}

const {flags} = cli
const params = omit(flags, ['limit', 'save', 'limitDays', 'show_info'])
const opts = Object.assign(pick(flags, ['limit', 'limitDays']), {credentials})

const stream = fetchTimeline(params, opts)
const writables = [ process.stdout ]
const {save, showInfo} = flags
let endMessage

if (save) {
  const identifier = getIdentifier(params)
  const filename = isString(save)
    ? save
    : `${identifier}.${fileDate()}.json`

  endMessage = `Saved at '${filename}'.`
  writables.push(fs.createWriteStream(filename))
}

const writable = multi(writables)

stream
  .pipe(JSONStream.stringify('[', ',\n', ']\n', 2))
  .pipe(writable)

stream.on('error', function (err) {
  // TODO: Create a better error message with res headers:
  // X-Rate-Limit-Limit: the rate limit ceiling for that given request
  // X-Rate-Limit-Remaining: the number of requests left for the 15 minute window
  // X-Rate-Limit-Reset: the remaining window before the rate limit resets in UTC epoch seconds
  const {statusCode, message: errMessage, code} = err
  const message = `${statusCode}: ${errMessage}`
  exitOnError(message, code)
})

if (showInfo) {
  stream.on('info', function (info) {
    const {apiCalls, count, newerTweetDate, olderTweetDate} = info
    const screenName = get(info, 'user.screen_name')

    setTimeout(function () {
      lineBreak()
      log.info(`${chalk.white('Total API calls  :')} ${apiCalls} calls`)
      log.info(`${chalk.white('Total tweets     :')} ${count} tweets`)

      if (count) {
        const now = Date.now()
        const newer = dateTime(newerTweetDate)
        const older = dateTime(olderTweetDate)
        const newerAgo = prettyMs(now - newerTweetDate.getTime())
        const olderAgo = prettyMs(now - olderTweetDate.getTime())

        log.info(`${chalk.white('Newer tweet date :')} ${newer} (${newerAgo})`)
        log.info(`${chalk.white('Older tweet date :')} ${older} (${olderAgo})`)
      }

      if (screenName) {
        const twitterUrl = `https://twitter.com/${screenName}`
        log.info(`${chalk.white('User profile     :')} ${twitterUrl}`)
      }

      if (endMessage) {
        lineBreak()
        log.success(endMessage)
      }
    }, 250)
  })
}
<|endoftext|>


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

const Nofan = require('../lib/nofan')
const program = require('commander')
const ora = require('ora')
const updateNotifier = require('update-notifier')
const pkg = require('../package')

updateNotifier({pkg}).notify()

program
  .option('-v, --version', 'output the version info')
  .option('-t, --time', 'show time ago tag')
  .option('--no-photo-tag', 'hide photo tag')
  .version(Nofan.version())

program
  .command('config [consumer_key] [consumer_secret]')
  .option('-a, --all', 'show all config')
  .description('config consumer key and consumer secret')
  .action(function (key, secret, options) {
    const showAll = options.all
    Nofan.config(key, secret, showAll)
  })

program
  .command('colors')
  .description('customize color style')
  .action(function () {
    Nofan.colors()
  })

program
  .command('login [username] [password]')
  .description('login nofan')
  .action(function (username, password) {
    Nofan.login(username, password)
  })

program
  .command('logout')
  .description('logout nofan')
  .action(function () {
    Nofan.logout()
  })

program
  .command('switch [id]')
  .alias('s')
  .description('switch account')
  .action(function (id) {
    Nofan.switchUser(id)
  })

program
  .command('home [count]')
  .alias('h')
  .description('show home timeline')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.homeTimeline({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('mentions [count]')
  .alias('m')
  .description('show mentions')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.mentions({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('me [count]')
  .description('show my statuses')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.me({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('public [count]')
  .alias('p')
  .description('show public timeline')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.publicTimeline({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('undo')
  .description('delete last status')
  .action(function () {
    process.spinner = ora('Deleting').start()
    Nofan.undo()
  })

program
  .arguments('<status> [more...]')
  .option('-p, --photo <path>', 'attach a photo')
  .description('')
  .action(function (pre, more, options) {
    process.spinner = ora('Sending').start()
    more.unshift(pre)
    const text = more.join(' ')
    if (!options.photo) Nofan.update(text)
    else Nofan.upload(options.photo, text)
  })

program.parse(process.argv)

if (program.args.length === 0) {
  process.spinner = ora('Fetching').start()
  Nofan.homeTimeline({
    time_ago: program.time,
    no_photo_tag: !program.photoTag
  })
}
<commit_msg>Add alias<commit_after>#!/usr/bin/env node

const Nofan = require('../lib/nofan')
const program = require('commander')
const ora = require('ora')
const updateNotifier = require('update-notifier')
const pkg = require('../package')

updateNotifier({pkg}).notify()

program
  .option('-v, --version', 'Output the version info')
  .option('-t, --time', 'Show time ago tag')
  .option('--no-photo-tag', 'Hide photo tag')
  .version(Nofan.version())

program
  .command('config [consumer_key] [consumer_secret]')
  .option('-a, --all', 'Show all config')
  .description('Config consumer key and consumer secret')
  .action(function (key, secret, options) {
    const showAll = options.all
    Nofan.config(key, secret, showAll)
  })

program
  .command('colors')
  .alias('color')
  .description('Customize color style')
  .action(function () {
    Nofan.colors()
  })

program
  .command('login [username] [password]')
  .description('Login nofan')
  .action(function (username, password) {
    Nofan.login(username, password)
  })

program
  .command('logout')
  .description('Logout nofan')
  .action(function () {
    Nofan.logout()
  })

program
  .command('switch [id]')
  .alias('s')
  .description('Switch account')
  .action(function (id) {
    Nofan.switchUser(id)
  })

program
  .command('home [count]')
  .alias('h')
  .description('Show home timeline')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.homeTimeline({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('mentions [count]')
  .alias('mention')
  .alias('m')
  .description('Show mentions')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.mentions({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('me [count]')
  .description('Show my statuses')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.me({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('public [count]')
  .alias('p')
  .description('Show public timeline')
  .action(function (count, options) {
    process.spinner = ora('Fetching').start()
    Nofan.publicTimeline({
      count: count,
      time_ago: options.parent.time,
      no_photo_tag: !options.parent.photoTag
    })
  })

program
  .command('undo')
  .description('Delete last status')
  .action(function () {
    process.spinner = ora('Deleting').start()
    Nofan.undo()
  })

program
  .arguments('<status> [more...]')
  .option('-p, --photo <path>', 'Attach a photo')
  .description('')
  .action(function (pre, more, options) {
    process.spinner = ora('Sending').start()
    more.unshift(pre)
    const text = more.join(' ')
    if (!options.photo) Nofan.update(text)
    else Nofan.upload(options.photo, text)
  })

program.parse(process.argv)

if (program.args.length === 0) {
  process.spinner = ora('Fetching').start()
  Nofan.homeTimeline({
    time_ago: program.time,
    no_photo_tag: !program.photoTag
  })
}
<|endoftext|>


<commit_before>/**
 *  Easy Edit Suite configuration options.
 *  This is an example, options may vary per EES implementation.
 *  More help on EES install and implementatuon can be found at http://manuals.matrix.squizsuite.net/ees/chapters/installation/
 */
var EasyEditConfig = {

    // Internal debugging flag. Setting this value to true will log debugging data
    // to the console in browsers that support console.log.
    // Quietly ignored in browsers that do not support console.log.
    debug:                      false,

    // The title bar that is displayed for EES.
    // @asset_name@ is a dynamic replacement for the current assets name.
    titleBar:                   "@asset_name@ : James Cook University Edit+",

    // Lock refresh interval in seconds.
    // EES automatically refreshed all locks for an asset based on this value.
    lockRefreshInterval:        120,

    // Array of base site urls. (Replaces 'eesSiteURL' global variable from EES builds 832 and 833)
    // For the majority systems, this can stay empty.
    // If required, the array of URLs should match up with urls applied in the Squiz Matrix system configuration.
    // If this is left empty or EES is installed on a site url that doesn't match a base site url then
    // a domain relative url will be used.
    baseSiteUrls: [],

    // JS API configuration options.
    // Populate with the API key found on the EES related JS API details screen.
    JSAPI: {
        key:                    "1881698051"
    },

    // Cascade status change threshold.
    // If a user selects 'Cascade Status Change' on the Details Screen and the
    // total number of child assets exceeds this value they will be
    // presented with a prompt to continue or to return to the screen.
    cascadeThreshold:           4,

    // Timeout to show a warning for overlays that are active for more than X number of
    // seconds. This is usually because of an ajax function that has for whatever
    // reason failed to return successfully and could indicate server error.
    overlayTimeout:             180,

    // PERFORMANCE FEATURE.
    // The default mode to use on initial load. Can be 'edit' or 'preview'.
    // Can be overridden in the url by using the hash #mode=mode_name e.g. #mode=preview.
    // If missing from config defaults to edit mode.
    defaultMode:                'edit',

    // Default screen to use on initial edit mode load.
    // Can be overridden in the url by using the hash #screen=screen_name e.g. #screen=content.
    // If missing from config defaults to details screen.
    defaultScreen:              'details',

    // Should the ?SQ_ACTION=diff flag be used in preview mode?
    // If missing from config or set to false preview mode will require
    // user interaction with the 'Compare to Live' button.
    showDifferencesInPreviewMode: false,

    // PERFORMANCE FEATURE.
    // Cache the asset finder results. If missing from config or false defaults to no cache.
    assetFinderCacheEnabled:      true,

    // Array of additional asset finder locations.
    // This can be used to add asset id's of frequently used site parents e.g. News, Events, Images.
    assetFinderLocations:         [364590,283019,2311,70],

    // PERFORMANCE FEATURE.
    // Maximum number of assets to show in an asset finder panel before
    // pagination occurs.
    // If missing from config pagination will default to 100.
    // 0 = no pagination.
    assetFinderMaxAssets:         100,

    // PERFORMANCE FEATURE.
    // Cache manager default expiry, minutes expressed as a whole number.
    cacheManagerDefaultExpiry:    2,

    // Show 'Set Thumbnail' section on details screen.
    // Adds the ability to add/remove/update a thumbnail to all assets.
    // If missing from config thumbnail will show by default, set to false to hide.
    useThumbnail:                true,

    // Display and allow editing of future statuses via the details screen.
    // If missing from config or false the details screen will not display 'Show Future Status'.
    allowFutureStatusChange:     true,

    // PERFORMANCE FEATURE.
    // Display a list of direct children on the link screen.
    // If missing from config or false the linking screen will not display 'Direct Children'.
    showChildrenOnLinkingScreen: true,

    //GOOGLE ANALYTICS CONNECTOR
    // A new Analytics screen will be made available for your assets, displaying the analytics data of your assets.
    analyticsViewId:             318119,

    // SITE EDITING (for Matrix 5.4)
    // This option allows you to enable the editing of Site Assets within Edit+.
    enableSiteEditing:           true

}; // End EasyEditConfig.
<commit_msg>Enable markdown content type for Edit+<commit_after>/**
 *  Easy Edit Suite configuration options.
 *  This is an example, options may vary per EES implementation.
 *  More help on EES install and implementatuon can be found at http://manuals.matrix.squizsuite.net/ees/chapters/installation/
 */
var EasyEditConfig = {

    // Internal debugging flag. Setting this value to true will log debugging data
    // to the console in browsers that support console.log.
    // Quietly ignored in browsers that do not support console.log.
    debug:                      false,

    // The title bar that is displayed for EES.
    // @asset_name@ is a dynamic replacement for the current assets name.
    titleBar:                   "@asset_name@ : James Cook University Edit+",

    // Lock refresh interval in seconds.
    // EES automatically refreshed all locks for an asset based on this value.
    lockRefreshInterval:        120,

    // Array of base site urls. (Replaces 'eesSiteURL' global variable from EES builds 832 and 833)
    // For the majority systems, this can stay empty.
    // If required, the array of URLs should match up with urls applied in the Squiz Matrix system configuration.
    // If this is left empty or EES is installed on a site url that doesn't match a base site url then
    // a domain relative url will be used.
    baseSiteUrls: [],

    // JS API configuration options.
    // Populate with the API key found on the EES related JS API details screen.
    JSAPI: {
        key:                    "1881698051"
    },

    // Cascade status change threshold.
    // If a user selects 'Cascade Status Change' on the Details Screen and the
    // total number of child assets exceeds this value they will be
    // presented with a prompt to continue or to return to the screen.
    cascadeThreshold:           4,

    // Timeout to show a warning for overlays that are active for more than X number of
    // seconds. This is usually because of an ajax function that has for whatever
    // reason failed to return successfully and could indicate server error.
    overlayTimeout:             180,

    // PERFORMANCE FEATURE.
    // The default mode to use on initial load. Can be 'edit' or 'preview'.
    // Can be overridden in the url by using the hash #mode=mode_name e.g. #mode=preview.
    // If missing from config defaults to edit mode.
    defaultMode:                'edit',

    // Default screen to use on initial edit mode load.
    // Can be overridden in the url by using the hash #screen=screen_name e.g. #screen=content.
    // If missing from config defaults to details screen.
    defaultScreen:              'details',

    // Should the ?SQ_ACTION=diff flag be used in preview mode?
    // If missing from config or set to false preview mode will require
    // user interaction with the 'Compare to Live' button.
    showDifferencesInPreviewMode: false,

    // PERFORMANCE FEATURE.
    // Cache the asset finder results. If missing from config or false defaults to no cache.
    assetFinderCacheEnabled:      true,

    // Array of additional asset finder locations.
    // This can be used to add asset id's of frequently used site parents e.g. News, Events, Images.
    assetFinderLocations:         [364590,283019,2311,70],

    // PERFORMANCE FEATURE.
    // Maximum number of assets to show in an asset finder panel before
    // pagination occurs.
    // If missing from config pagination will default to 100.
    // 0 = no pagination.
    assetFinderMaxAssets:         100,

    // PERFORMANCE FEATURE.
    // Cache manager default expiry, minutes expressed as a whole number.
    cacheManagerDefaultExpiry:    2,

    // Show 'Set Thumbnail' section on details screen.
    // Adds the ability to add/remove/update a thumbnail to all assets.
    // If missing from config thumbnail will show by default, set to false to hide.
    useThumbnail:                true,

    // Display and allow editing of future statuses via the details screen.
    // If missing from config or false the details screen will not display 'Show Future Status'.
    allowFutureStatusChange:     true,

    // PERFORMANCE FEATURE.
    // Display a list of direct children on the link screen.
    // If missing from config or false the linking screen will not display 'Direct Children'.
    showChildrenOnLinkingScreen: true,

    //Google Analytics Connector
    // A new Analytics screen will be made available for your assets, displaying the analytics data of your assets.
    analyticsViewId:             318119,

    // Markdown content type for content containers
    markdownEnabled:             true,

    // Site Editing (For Matrix 5.4)
    // This option allows you to enable the editing of Site Assets within Edit+.
    enableSiteEditing:           true

}; // End EasyEditConfig.
<|endoftext|>


<commit_before>var argv = require('optimist').argv;
var fs = require('fs');
var parse = require('../lib/parse.js');

var output = process.stderr;
if (argv.o === '-' || argv.o === '@1') {
    output = process.stdout;
}
else if (argv.o && argv.o !== '@2') {
    output = fs.createWriteStream(argv.o);
}

process.stdin.pipe(parse(function (err, sources) {
    if (err) {
        console.error(err);
        process.exit(1);
    }
    else if (argv.json) {
        return output.write(JSON.stringify(sources, null, 2) + '\n');
    }
    else {
        Object.keys(sources).forEach(function (file) {
            if (sources[file].length === 0) return;

            sources[file].forEach(function (m) {
                var parts = [];
                parts.push(m.line.slice(0, m.column[0]));
                parts.push('\x1b[31m\x1b[1m');
                parts.push(m.line.slice(m.column[0], m.column[1]));
                parts.push('\x1b[0m');
                parts.push(m.line.slice(m.column[1]));

                var s = parts.join('');
                output.write(
                    '# ' + file
                    + ': line ' + m.lineNum
                    + ', column ' + m.column.join('-')
                    + '\n\n'
                );
                output.write('  ' + s.trim() + '\n');

                var xxx = m.line.replace(/\S/g, 'x');
                var xparts = [];
                xparts.push(xxx.slice(0, m.column[0] + 1));
                xparts.push(Array(m.column[1] - m.column[0]).join('^'));
                var sx = xparts.join('').trim().replace(/x/g, ' ');
                output.write('  ' + sx + '\n\n');
            });
        });
    }
})).pipe(process.stdout);
<commit_msg>non-zero exit code when coverage is not 100%<commit_after>var argv = require('optimist').argv;
var fs = require('fs');
var parse = require('../lib/parse.js');

var output = process.stderr;
if (argv.o === '-' || argv.o === '@1') {
    output = process.stdout;
}
else if (argv.o && argv.o !== '@2') {
    output = fs.createWriteStream(argv.o);
}

var covered = true;
process.on('exit', function (code) {
    if (!covered) process.exit(1);
});

process.stdin.pipe(parse(function (err, sources) {
    if (err) {
        console.error(err);
        process.exit(1);
    }
    else if (argv.json) {
        return output.write(JSON.stringify(sources, null, 2) + '\n');
    }
    else {
        Object.keys(sources).forEach(function (file) {
            if (sources[file].length === 0) return;

            sources[file].forEach(function (m) {
                covered = false;

                var parts = [];
                parts.push(m.line.slice(0, m.column[0]));
                parts.push('\x1b[31m\x1b[1m');
                parts.push(m.line.slice(m.column[0], m.column[1]));
                parts.push('\x1b[0m');
                parts.push(m.line.slice(m.column[1]));

                var s = parts.join('');
                output.write(
                    '# ' + file
                    + ': line ' + m.lineNum
                    + ', column ' + m.column.join('-')
                    + '\n\n'
                );
                output.write('  ' + s.trim() + '\n');

                var xxx = m.line.replace(/\S/g, 'x');
                var xparts = [];
                xparts.push(xxx.slice(0, m.column[0] + 1));
                xparts.push(Array(m.column[1] - m.column[0]).join('^'));
                var sx = xparts.join('').trim().replace(/x/g, ' ');
                output.write('  ' + sx + '\n\n');
            });
        });
    }
})).pipe(process.stdout);
<|endoftext|>


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

// Native
const http = require('http');
const path = require('path');
const fs = require('fs');
const {promisify} = require('util');
const {parse} = require('url');
const dns = require('dns');
const os = require('os');

// Packages
const Ajv = require('ajv');
const checkForUpdate = require('update-check');
const chalk = require('chalk');
const arg = require('arg');
const {write: copy} = require('clipboardy');
const handler = require('serve-handler');
const schema = require('@zeit/schemas/deployment/config-static');
const boxen = require('boxen');

// Utilities
const pkg = require('../package');

const readFile = promisify(fs.readFile);
const lookup = promisify(dns.lookup);

const warning = message => chalk`{yellow WARNING:} ${message}`;
const info = message => chalk`{magenta INFO:} ${message}`;
const error = message => chalk`{red ERROR:} ${message}`;

const updateCheck = async isDebugging => {
	let update = null;

	try {
		update = await checkForUpdate(pkg);
	} catch (err) {
		const suffix = isDebugging ? ':' : ' (use `--debug` to see full error)';
		console.error(warning(`Checking for updates failed${suffix}`));

		if (isDebugging) {
			console.error(err);
		}
	}

	if (!update) {
		return;
	}

	console.log(`${chalk.bgRed('UPDATE AVAILABLE')} The latest version of \`serve\` is ${update.latest}`);
};

const getHelp = () => chalk`
  {bold.cyan serve} - Static file serving and directory listing

  {bold USAGE}

      {bold $} {cyan serve} --help
      {bold $} {cyan serve} --version
      {bold $} {cyan serve} [-l {underline listen_uri} [-l ...]] [{underline directory}]

      By default, {cyan serve} will listen on {bold 0.0.0.0:5000} and serve the
      current working directory on that address.

      Specifying a single {bold --listen} argument will overwrite the default, not supplement it.

  {bold OPTIONS}

      --help                              Shows this help message

      -v, --version                       Displays the current version of serve

      -l, --listen {underline listen_uri}             Specify a URI endpoint on which to listen (see below) -
                                          more than one may be specified to listen in multiple places

      -d, --debug                         Show debugging information

      -s, --single                        Rewrite all not-found requests to \`index.html\`

      -c, --config                        Specify custom path to \`serve.json\`

      -n, --no-clipboard                  Do not copy the local address to the clipboard

  {bold ENDPOINTS}

      Listen endpoints (specified by the {bold --listen} or {bold -l} options above) instruct {cyan serve}
      to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.

      For TCP ports on hostname "localhost":

          {bold $} {cyan serve} -l {underline 1234}

      For TCP (traditional host/port) endpoints:

          {bold $} {cyan serve} -l tcp://{underline hostname}:{underline 1234}

      For UNIX domain socket endpoints:

          {bold $} {cyan serve} -l unix:{underline /path/to/socket.sock}

      For Windows named pipe endpoints:

          {bold $} {cyan serve} -l pipe:\\\\.\\pipe\\{underline PipeName}
`;

const parseEndpoint = str => {
	if (!isNaN(str)) {
		return [str];
	}

	// We cannot use `new URL` here, otherwise it will not
	// parse the host properly and it would drop support for IPv6.
	const url = parse(str);

	switch (url.protocol) {
	case 'pipe:': {
		// some special handling
		const cutStr = str.replace(/^pipe:/, '');

		if (cutStr.slice(0, 4) !== '\\\\.\\') {
			throw new Error(`Invalid Windows named pipe endpoint: ${str}`);
		}

		return [cutStr];
	}
	case 'unix:':
		if (!url.pathname) {
			throw new Error(`Invalid UNIX domain socket endpoint: ${str}`);
		}

		return [url.pathname];
	case 'tcp:':
		url.port = url.port || '5000';
		return [parseInt(url.port, 10), url.hostname];
	default:
		throw new Error(`Unknown --listen endpoint scheme (protocol): ${url.protocol}`);
	}
};

const registerShutdown = fn => {
	let run = false;

	const wrapper = () => {
		if (!run) {
			run = true;
			fn();
		}
	};

	process.on('SIGINT', wrapper);
	process.on('SIGTERM', wrapper);
	process.on('exit', wrapper);
};

const startEndpoint = (endpoint, config, args) => {
	const server = http.createServer((request, response) => handler(request, response, config));
	const {isTTY} = process.stdout;
	const clipboard = args['--no-clipboard'] !== true;

	server.on('error', err => {
		console.error(error(`Failed to serve: ${err.stack}`));
		process.exit(1);
	});

	server.listen(...endpoint, async () => {
		const details = server.address();
		registerShutdown(() => server.close());

		let localAddress = null;
		let networkAddress = null;

		if (typeof details === 'string') {
			localAddress = details;
		} else if (typeof details === 'object' && details.port) {
			const address = details.address === '::' ? 'localhost' : details.address;
			const {address: ip} = await lookup(os.hostname());

			localAddress = `http://${address}:${details.port}`;
			networkAddress = `http://${ip}:${details.port}`;
		}

		if (isTTY && process.env.NODE_ENV !== 'production') {
			let message = chalk.green('Serving!');

			if (localAddress) {
				const prefix = networkAddress ? '- ' : '';
				const space = networkAddress ? '            ' : '  ';

				message += `\n\n${chalk.bold(`${prefix}Local:`)}${space}${localAddress}`;
			}

			if (networkAddress) {
				message += `\n${chalk.bold('- On Your Network:')}  ${networkAddress}`;
			}

			if (clipboard) {
				try {
					await copy(localAddress);
					message += `\n\n${chalk.grey('Copied local address to clipboard!')}`;
				} catch (err) {
					console.error(error(`Cannot copy to clipboard: ${err.message}`));
				}
			}

			console.log(boxen(message, {
				padding: 1,
				borderColor: 'green',
				margin: 1
			}));
		} else {
			const suffix = localAddress ? ` at ${localAddress}` : '';
			console.log(info(`Accepting connections${suffix}`));
		}
	});
};

const loadConfig = async (cwd, entry, args) => {
	const files = [
		'serve.json',
		'now.json',
		'package.json'
	];

	if (args['--config']) {
		files.unshift(args['--config']);
	}

	const config = {};

	for (const file of files) {
		const location = path.join(entry, file);
		let content = null;

		try {
			content = await readFile(location, 'utf8');
		} catch (err) {
			if (err.code === 'ENOENT') {
				continue;
			}

			console.error(error(`Not able to read ${location}: ${err.message}`));
			process.exit(1);
		}

		try {
			content = JSON.parse(content);
		} catch (err) {
			console.error(error(`Could not parse ${location} as JSON: ${err.message}`));
			process.exit(1);
		}

		if (typeof content !== 'object') {
			console.error(warning(`Didn't find a valid object in ${location}. Skipping...`));
			continue;
		}

		try {
			switch (file) {
			case 'now.json':
				content = content.static;
				break;
			case 'package.json':
				content = content.now.static;
				break;
			}
		} catch (err) {
			continue;
		}

		Object.assign(config, content);
		console.log(info(`Discovered configuration in \`${file}\``));

		break;
	}

	if (entry) {
		const {public} = config;
		config.public = path.relative(cwd, (public ? path.join(entry, public) : entry));
	}

	if (Object.keys(config).length !== 0) {
		const ajv = new Ajv();
		const validateSchema = ajv.compile(schema);

		if (!validateSchema(config)) {
			const defaultMessage = error('The configuration you provided is wrong:');
			const {message, params} = validateSchema.errors[0];

			console.error(`${defaultMessage}\n${message}\n${JSON.stringify(params)}`);
			process.exit(1);
		}
	}

	return config;
};

(async () => {
	let args = null;

	try {
		args = arg({
			'--help': Boolean,
			'--version': Boolean,
			'--listen': [parseEndpoint],
			'--single': Boolean,
			'--debug': Boolean,
			'--config': String,
			'--no-clipboard': Boolean,
			'-h': '--help',
			'-v': '--version',
			'-l': '--listen',
			'-s': '--single',
			'-d': '--debug',
			'-c': '--config',
			'-n': '--no-clipboard',
			// This is deprecated and only for backwards-compatibility.
			'-p': '--listen'
		});
	} catch (err) {
		console.error(error(err.message));
		process.exit(1);
	}

	await updateCheck(args['--debug']);

	if (args['--version']) {
		console.log(pkg.version);
		return;
	}

	if (args['--help']) {
		console.log(getHelp());
		return;
	}

	if (!args['--listen']) {
		// Default endpoint
		args['--listen'] = [[process.env.PORT || 5000]];
	}

	if (args._.length > 1) {
		console.error(error('Please provide one path argument at maximum'));
		process.exit(1);
	}

	const cwd = process.cwd();
	const entry = args._.length > 0 ? path.join(cwd, args._[0]) : cwd;

	const config = await loadConfig(cwd, entry, args);

	if (args['--single']) {
		const {rewrites} = config;
		const existingRewrites = Array.isArray(rewrites) ? rewrites : [];

		// As the first rewrite rule, make `--single` work
		config.rewrites = [{
			source: '**',
			destination: '/index.html'
		}, ...existingRewrites];
	}

	for (const endpoint of args['--listen']) {
		startEndpoint(endpoint, config, args);
	}

	registerShutdown(() => {
		console.log(`\n${info('Gracefully shutting down. Please wait...')}`);

		process.on('SIGINT', () => {
			console.log(`\n${warning('Force-closing all open sockets...')}`);
			process.exit(0);
		});
	});
})();
<commit_msg>Handle DNS lookup failures (#439)<commit_after>#!/usr/bin/env node

// Native
const http = require('http');
const path = require('path');
const fs = require('fs');
const {promisify} = require('util');
const {parse} = require('url');
const dns = require('dns');
const os = require('os');

// Packages
const Ajv = require('ajv');
const checkForUpdate = require('update-check');
const chalk = require('chalk');
const arg = require('arg');
const {write: copy} = require('clipboardy');
const handler = require('serve-handler');
const schema = require('@zeit/schemas/deployment/config-static');
const boxen = require('boxen');

// Utilities
const pkg = require('../package');

const readFile = promisify(fs.readFile);
const lookup = promisify(dns.lookup);

const warning = message => chalk`{yellow WARNING:} ${message}`;
const info = message => chalk`{magenta INFO:} ${message}`;
const error = message => chalk`{red ERROR:} ${message}`;

const updateCheck = async isDebugging => {
	let update = null;

	try {
		update = await checkForUpdate(pkg);
	} catch (err) {
		const suffix = isDebugging ? ':' : ' (use `--debug` to see full error)';
		console.error(warning(`Checking for updates failed${suffix}`));

		if (isDebugging) {
			console.error(err);
		}
	}

	if (!update) {
		return;
	}

	console.log(`${chalk.bgRed('UPDATE AVAILABLE')} The latest version of \`serve\` is ${update.latest}`);
};

const getHelp = () => chalk`
  {bold.cyan serve} - Static file serving and directory listing

  {bold USAGE}

      {bold $} {cyan serve} --help
      {bold $} {cyan serve} --version
      {bold $} {cyan serve} [-l {underline listen_uri} [-l ...]] [{underline directory}]

      By default, {cyan serve} will listen on {bold 0.0.0.0:5000} and serve the
      current working directory on that address.

      Specifying a single {bold --listen} argument will overwrite the default, not supplement it.

  {bold OPTIONS}

      --help                              Shows this help message

      -v, --version                       Displays the current version of serve

      -l, --listen {underline listen_uri}             Specify a URI endpoint on which to listen (see below) -
                                          more than one may be specified to listen in multiple places

      -d, --debug                         Show debugging information

      -s, --single                        Rewrite all not-found requests to \`index.html\`

      -c, --config                        Specify custom path to \`serve.json\`

      -n, --no-clipboard                  Do not copy the local address to the clipboard

  {bold ENDPOINTS}

      Listen endpoints (specified by the {bold --listen} or {bold -l} options above) instruct {cyan serve}
      to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.

      For TCP ports on hostname "localhost":

          {bold $} {cyan serve} -l {underline 1234}

      For TCP (traditional host/port) endpoints:

          {bold $} {cyan serve} -l tcp://{underline hostname}:{underline 1234}

      For UNIX domain socket endpoints:

          {bold $} {cyan serve} -l unix:{underline /path/to/socket.sock}

      For Windows named pipe endpoints:

          {bold $} {cyan serve} -l pipe:\\\\.\\pipe\\{underline PipeName}
`;

const parseEndpoint = str => {
	if (!isNaN(str)) {
		return [str];
	}

	// We cannot use `new URL` here, otherwise it will not
	// parse the host properly and it would drop support for IPv6.
	const url = parse(str);

	switch (url.protocol) {
	case 'pipe:': {
		// some special handling
		const cutStr = str.replace(/^pipe:/, '');

		if (cutStr.slice(0, 4) !== '\\\\.\\') {
			throw new Error(`Invalid Windows named pipe endpoint: ${str}`);
		}

		return [cutStr];
	}
	case 'unix:':
		if (!url.pathname) {
			throw new Error(`Invalid UNIX domain socket endpoint: ${str}`);
		}

		return [url.pathname];
	case 'tcp:':
		url.port = url.port || '5000';
		return [parseInt(url.port, 10), url.hostname];
	default:
		throw new Error(`Unknown --listen endpoint scheme (protocol): ${url.protocol}`);
	}
};

const registerShutdown = fn => {
	let run = false;

	const wrapper = () => {
		if (!run) {
			run = true;
			fn();
		}
	};

	process.on('SIGINT', wrapper);
	process.on('SIGTERM', wrapper);
	process.on('exit', wrapper);
};

const startEndpoint = (endpoint, config, args) => {
	const server = http.createServer((request, response) => handler(request, response, config));
	const {isTTY} = process.stdout;
	const clipboard = args['--no-clipboard'] !== true;

	server.on('error', err => {
		console.error(error(`Failed to serve: ${err.stack}`));
		process.exit(1);
	});

	server.listen(...endpoint, async () => {
		const details = server.address();
		registerShutdown(() => server.close());

		let localAddress = null;
		let networkAddress = null;

		if (typeof details === 'string') {
			localAddress = details;
		} else if (typeof details === 'object' && details.port) {
			const address = details.address === '::' ? 'localhost' : details.address;

			localAddress = `http://${address}:${details.port}`;
			try {
				const {address: ip} = await lookup(os.hostname());
				networkAddress = `http://${ip}:${details.port}`;
			} catch (err) {
				console.error(error(`DNS lookup failed: ${err.message}`));
			}
		}

		if (isTTY && process.env.NODE_ENV !== 'production') {
			let message = chalk.green('Serving!');

			if (localAddress) {
				const prefix = networkAddress ? '- ' : '';
				const space = networkAddress ? '            ' : '  ';

				message += `\n\n${chalk.bold(`${prefix}Local:`)}${space}${localAddress}`;
			}

			if (networkAddress) {
				message += `\n${chalk.bold('- On Your Network:')}  ${networkAddress}`;
			}

			if (clipboard) {
				try {
					await copy(localAddress);
					message += `\n\n${chalk.grey('Copied local address to clipboard!')}`;
				} catch (err) {
					console.error(error(`Cannot copy to clipboard: ${err.message}`));
				}
			}

			console.log(boxen(message, {
				padding: 1,
				borderColor: 'green',
				margin: 1
			}));
		} else {
			const suffix = localAddress ? ` at ${localAddress}` : '';
			console.log(info(`Accepting connections${suffix}`));
		}
	});
};

const loadConfig = async (cwd, entry, args) => {
	const files = [
		'serve.json',
		'now.json',
		'package.json'
	];

	if (args['--config']) {
		files.unshift(args['--config']);
	}

	const config = {};

	for (const file of files) {
		const location = path.join(entry, file);
		let content = null;

		try {
			content = await readFile(location, 'utf8');
		} catch (err) {
			if (err.code === 'ENOENT') {
				continue;
			}

			console.error(error(`Not able to read ${location}: ${err.message}`));
			process.exit(1);
		}

		try {
			content = JSON.parse(content);
		} catch (err) {
			console.error(error(`Could not parse ${location} as JSON: ${err.message}`));
			process.exit(1);
		}

		if (typeof content !== 'object') {
			console.error(warning(`Didn't find a valid object in ${location}. Skipping...`));
			continue;
		}

		try {
			switch (file) {
			case 'now.json':
				content = content.static;
				break;
			case 'package.json':
				content = content.now.static;
				break;
			}
		} catch (err) {
			continue;
		}

		Object.assign(config, content);
		console.log(info(`Discovered configuration in \`${file}\``));

		break;
	}

	if (entry) {
		const {public} = config;
		config.public = path.relative(cwd, (public ? path.join(entry, public) : entry));
	}

	if (Object.keys(config).length !== 0) {
		const ajv = new Ajv();
		const validateSchema = ajv.compile(schema);

		if (!validateSchema(config)) {
			const defaultMessage = error('The configuration you provided is wrong:');
			const {message, params} = validateSchema.errors[0];

			console.error(`${defaultMessage}\n${message}\n${JSON.stringify(params)}`);
			process.exit(1);
		}
	}

	return config;
};

(async () => {
	let args = null;

	try {
		args = arg({
			'--help': Boolean,
			'--version': Boolean,
			'--listen': [parseEndpoint],
			'--single': Boolean,
			'--debug': Boolean,
			'--config': String,
			'--no-clipboard': Boolean,
			'-h': '--help',
			'-v': '--version',
			'-l': '--listen',
			'-s': '--single',
			'-d': '--debug',
			'-c': '--config',
			'-n': '--no-clipboard',
			// This is deprecated and only for backwards-compatibility.
			'-p': '--listen'
		});
	} catch (err) {
		console.error(error(err.message));
		process.exit(1);
	}

	await updateCheck(args['--debug']);

	if (args['--version']) {
		console.log(pkg.version);
		return;
	}

	if (args['--help']) {
		console.log(getHelp());
		return;
	}

	if (!args['--listen']) {
		// Default endpoint
		args['--listen'] = [[process.env.PORT || 5000]];
	}

	if (args._.length > 1) {
		console.error(error('Please provide one path argument at maximum'));
		process.exit(1);
	}

	const cwd = process.cwd();
	const entry = args._.length > 0 ? path.join(cwd, args._[0]) : cwd;

	const config = await loadConfig(cwd, entry, args);

	if (args['--single']) {
		const {rewrites} = config;
		const existingRewrites = Array.isArray(rewrites) ? rewrites : [];

		// As the first rewrite rule, make `--single` work
		config.rewrites = [{
			source: '**',
			destination: '/index.html'
		}, ...existingRewrites];
	}

	for (const endpoint of args['--listen']) {
		startEndpoint(endpoint, config, args);
	}

	registerShutdown(() => {
		console.log(`\n${info('Gracefully shutting down. Please wait...')}`);

		process.on('SIGINT', () => {
			console.log(`\n${warning('Force-closing all open sockets...')}`);
			process.exit(0);
		});
	});
})();
<|endoftext|>


<commit_before>angular
	.module(`${window.APP_NAME}.pages`)
	.directive('entitiesZone', entitiesZoneDirective);

const TEMPLATE = `

Entities

		<select ng-model="ctrl.entityType" ng-options="type as type for type in ctrl.entityTypes">
		</select>

		<input class="zone-input" type="text" ng-model="ctrl.query">
		<input class="zone-input" type="text" ng-model="ctrl.sort">
		<button ng-click="ctrl.getData()">Update</button>

					id
					Name
					Author
					Creation Date

				{{::item._id}}
				{{::item.name}}
				{{::item.author.name}}

Actions

Rename

			<input class="zone-input" type="text" ng-model="renameId">
			<input class="zone-input" type="text" ng-model="renameNewName">
			<button ng-click="ctrl.rename(ctrl.entityType, renameId, renameNewName)">Rename</button>

Merge

			<input class="zone-input" type="text" ng-model="mergeFromId">
			<input class="zone-input" type="text" ng-model="mergeToId">
			<button ng-click="ctrl.merge(ctrl.entityType, mergeFromId, mergeToId)">Merge</button>

`;

// entity types
const ENTITY_TYPES = [
	'tournaments',
	'teams',
	'casters'
];

function entitiesZoneDirective () {

	return {
		restrict: 'E',
		controllerAs: 'ctrl',
		replace: true,
		scope: true,
		template: TEMPLATE,
		controller: controller
	};

	function controller ($http, Constants) {
		var self = this;

		self.data = {};
		self.query = '{}';
		self.sort = '{"_id": -1}';
		self.entityType = ENTITY_TYPES[1];
		self.entityTypes = ENTITY_TYPES;

		self.getData = getData;
		self.rename = rename;

		getData();

		function getData () {
			let url = `${Constants.Api.PREFIX}/${self.entityType}`;
			self.data = {};
			$http.get(url).then(response => self.data = response.data);
		}

		function rename (entityType, id, newName) {

		}
	}
}
<commit_msg>zone ui for entities updated<commit_after>angular
	.module(`${window.APP_NAME}.pages`)
	.directive('entitiesZone', entitiesZoneDirective);

const TEMPLATE = `

Entities

		<select ng-model="ctrl.entityType" ng-options="type as type for type in ctrl.entityTypes">
		</select>

		<input class="zone-input" type="text" ng-model="ctrl.query">
		<input class="zone-input" type="text" ng-model="ctrl.sort">
		<button ng-click="ctrl.getData()">Update</button>

					id
					Name
					Author
					Creation Date

				{{::item._id}}
				{{::item.name}}
				{{::item.author.name}}

Actions

Rename

			<input class="zone-input" type="text" ng-model="renameId" placeholder="ID">
			<input class="zone-input" type="text" ng-model="renameNewName" placeholder="New name">
			<button ng-click="ctrl.rename(renameId, renameNewName)">Rename</button>

Merge

			<input class="zone-input" type="text" ng-model="mergeFromId" placeholder="Source ID">
			<input class="zone-input" type="text" ng-model="mergeToId" placeholder="Target ID">
			<button ng-click="ctrl.merge(mergeFromId, mergeToId)">Merge</button>

`;

// entity types
const ENTITY_TYPES = [
	'tournaments',
	'teams',
	'casters'
];

function entitiesZoneDirective () {

	return {
		restrict: 'E',
		controllerAs: 'ctrl',
		replace: true,
		scope: true,
		template: TEMPLATE,
		controller: controller
	};

	function controller ($http, Constants) {
		var self = this;

		self.data = {};
		self.query = '{}';
		self.sort = '{"_id": -1}';
		self.entityType = ENTITY_TYPES[1];
		self.entityTypes = ENTITY_TYPES;

		self.getData = getData;
		self.rename = rename;
		self.merge = merge;

		getData();

		function getData () {
			let url = `${Constants.Api.PREFIX}/${self.entityType}`;
			self.data = {};
			$http.get(url).then(response => self.data = response.data);
		}

		function rename (id, newName) {
			$http
				.put(`${Constants.Api.PREFIX}/${self.entityType.slice(0, -1)}`, {
					id,
					update: {name: newName}
				})
				.catch(e => alert(e)); // eslint-disable-line no-alert
		}

		function merge (src, target) {
			$http
				.post(`${Constants.Api.PREFIX}/${self.entityType.slice(0, -1)}/merge`, {
					src,
					target
				})
				.catch(e => alert(e)); // eslint-disable-line no-alert
		}
	}
}
<|endoftext|>


<commit_before>#! /usr/bin/env node
'use strict';
const defaultOption = require('../lib/defaultOption');
const glob = require('glob-all');
const minimist = require('minimist');
const path = require('path');
const pkg = require('../package.json');
const thout = require('../lib/');

const argv = minimist(process.argv.slice(2), {
  boolean: [
    'help',
    'version'
  ],
  alias: {
    t: 'timeout',
    h: 'help',
    v: 'version'
  },
  default: {
    timeout: 2000,
    help: false,
    version: false
  }
});

function main() {
  const options = {};
  const files = argv._;

  if (files.length > 0) {
    options.files = files;
  }
  if (argv.t) {
    options.timeout = argv.t;
  }

  thout.setup(Object.assign({}, defaultOption, options));

  glob.sync(files)
    .forEach((file) => {
      require(path.resolve(process.cwd(), file));
    });
}

function showHelp() {
  console.log(`
${pkg.description}

Usage
  ${Object.keys(pkg.bin)[0]} [options]

Options
  -h, --help       Show help.
  -v, --version    Print version.
`);
}

function showVersion() {
  console.log(pkg.version);
}

if (argv.help) {
  showHelp();
}

if (argv.version) {
  showVersion();
}

main();
<commit_msg>feat(cli): add --require options<commit_after>#! /usr/bin/env node
'use strict';
const defaultOption = require('../lib/defaultOption');
const fs = require('fs');
const globAll = require('glob-all');
const minimist = require('minimist');
const path = require('path');
const pkg = require('../package.json');
const thout = require('../lib/');

const existsSync = fs.existsSync || path.existsSync;

const argv = minimist(process.argv.slice(2), {
  string: [
    'require'
  ],
  boolean: [
    'help',
    'version'
  ],
  alias: {
    h: 'help',
    r: 'require',
    t: 'timeout',
    v: 'version'
  },
  default: {
    timeout: 2000,
    help: false,
    version: false
  }
});

function main() {
  const options = {};
  const files = argv._;
  let requires = [];

  if (files.length > 0) {
    options.files = files;
  }
  if (argv.t) {
    options.timeout = argv.t;
  }
  if (argv.r) {
    requires = argv.r;
    if (!Array.isArray(argv.r)) {
      requires = [argv.r];
    }
  }

  thout.setup(Object.assign({}, defaultOption, options));

  requires.forEach((mod) => {
    const isLocalFile = existsSync(mod) || existsSync(mod + '.js');
    const file = isLocalFile ? path.resolve(mod) : mod;
    require(file);
  });

  globAll.sync(files)
    .forEach((file) => {
      require(path.resolve(file));
    });
}

function showHelp() {
  console.log(`
${pkg.description}

Usage
  ${Object.keys(pkg.bin)[0]} [options]

Options
  -h, --help       Show help.
  -v, --version    Print version.
`);
}

function showVersion() {
  console.log(pkg.version);
}

if (argv.help) {
  showHelp();
}

if (argv.version) {
  showVersion();
}

main();
<|endoftext|>


<commit_before>/*
 * @requires plugins/Tool.js
 * @requires OpenLayers/Request.js
 * @include OpenLayers/Layer/Vector.js
 * @include OpenLayers/Strategy/BBOX.js
 * @include OpenLayers/Protocol/WFS/v1_0_0.js
 * @include OpenLayers/Protocol/WFS.js
 * @include OpenLayers/Protocol/HTTP.js
 * @include OpenLayers/Format/JSON.js
 * @include OpenLayers/Control/SelectFeature.js
 * @include GeoExt/widgets/tree/LayerNode.js
 * @include styles.js
 */

Ext.namespace("c2corg.plugins");

c2corg.plugins.LayerTree = Ext.extend(gxp.plugins.Tool, {

    ptype: "c2corg_layertree",

    init: function() {
        c2corg.plugins.LayerTree.superclass.init.apply(this, arguments);
        this.target.on("ready", this.viewerReady, this);
    },

    viewerReady: function() {
        this.tree.delayedApplyState();
        this.tree.loadInitialThemes();
        this.tree.makeThemesInteractive();
    },

    addOutput: function(config) {

        config = Ext.apply({
            xtype: "c2corg_layertree",
            mapPanel: this.target.mapPanel,
            url: this.url,
            initialThemes: this.initialThemes || []
        }, config || {});

        this.tree = c2corg.plugins.LayerTree.superclass.addOutput.call(this, config);
        this.tree.findParentByType("window").alignTo(this.target.mapPanel.getEl(), "tr-tr", [-20, 45]);
        return this.tree;
    }
});

Ext.preg(c2corg.plugins.LayerTree.prototype.ptype, c2corg.plugins.LayerTree);

Ext.namespace("c2corg.tree");

c2corg.tree.LayerTree = Ext.extend(Ext.tree.TreePanel, {

    baseCls: "layertree",
    enableDD: false,
    rootVisible: false,
    useArrows: true,

    mapPanel: null,
    initialState: null,
    initialThemes: null,

    stateEvents: ["layervisibilitychange"],
    stateId: "tree",

    url: null,
    layers: {},
    styleMap: null,

    initComponent: function() {
        this.addLayers();
        this.root = {
            children: this.getThemes()
        };
        c2corg.tree.LayerTree.superclass.initComponent.call(this, arguments);

        this.addEvents(
            /** private: event[layervisibilitychange]
             *  Fires after a checkbox state changes
             */
            "layervisibilitychange"
        );
        this.on("checkchange", function(node, checked) {
            this.fireEvent("layervisibilitychange");
        }, this);
    },

    getStyleMap: function() {
        if (!this.styleMap) {
            this.styleMap = c2corg.styleMap();
        }
        return this.styleMap;
    },

    createVectorLayer: function(options) {
        return new OpenLayers.Layer.Vector(options.name, {
            strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1, ratio: 1})],
            protocol: new OpenLayers.Protocol.WFS({
                featureType: options.featureType,
                url: this.url,
                maxFeatures: options.maxFeatures || 200,
                geometryName: "geom",
                srsName: "EPSG:900913"
            }),
            isBaseLayer: false,
            visibility: false,
            styleMap: this.getStyleMap()
        });
    },

    addLayers: function() {
        this.layers = {
            "summits": this.createVectorLayer({name: "summits", featureType: "summits"}),
            "access": this.createVectorLayer({name: "access", featureType: "access"}),
            "huts": this.createVectorLayer({name: "huts", featureType: "huts"}),
            "sites": this.createVectorLayer({name: "sites", featureType: "sites"}),
            "users": this.createVectorLayer({name: "users", featureType: "users"}),
            "images": this.createVectorLayer({name: "images", featureType: "images"}),
            "products": this.createVectorLayer({name: "products", featureType: "products"}),
            "routes": this.createVectorLayer({name: "routes", featureType: "routes", maxFeatures: 50}),
            "outings": this.createVectorLayer({name: "outings", featureType: "outings", maxFeatures: 50}),
            "maps": this.createVectorLayer({name: "maps", featureType: "maps"}),
            "ranges": this.createVectorLayer({name: "ranges", featureType: "ranges"}),
            "admin_limits": this.createVectorLayer({name: "admin_limits", featureType: "admin_limits"}),
            "countries": this.createVectorLayer({name: "countries", featureType: "countries"})
        };
        for (var i in this.layers) {
            this.mapPanel.map.addLayer(this.layers[i]);
        }
    },

    getThemes: function() {
        return [{
            text: OpenLayers.i18n("summits"),
            nodeType: "gx_layer",
            layer: this.layers["summits"],
            iconCls: "picto_summits",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("pass"),
                iconCls: "picto_pass",
                leaf: true
            },{
                text: OpenLayers.i18n("lake"),
                iconCls: "picto_lake",
                leaf: true
            },{
                text: OpenLayers.i18n("valley"),
                iconCls: "picto_crag",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("parkings"),
            nodeType: "gx_layer",
            layer: this.layers["access"],
            iconCls: "picto_parkings",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("public_transportations"),
                iconCls: "picto_parking_green",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("huts"),
            nodeType: "gx_layer",
            layer: this.layers["huts"],
            iconCls: "picto_huts",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("gite"),
                iconCls: "picto_gite",
                leaf: true
            }, {
                text: OpenLayers.i18n("camping area"),
                iconCls: "picto_camp",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("sites"),
            nodeType: "gx_layer",
            layer: this.layers["sites"],
            iconCls: "picto_sites",
            leaf: true
        }, {
            text: OpenLayers.i18n("routes"),
            nodeType: "gx_layer",
            layer: this.layers["routes"],
            iconCls: "picto_routes",
            leaf: true
        }, {
            text: OpenLayers.i18n("More..."),
            expanded: false,
            children: [{
                text: OpenLayers.i18n("users"),
                nodeType: "gx_layer",
                layer: this.layers["users"],
                iconCls: "picto_users",
                leaf: true
            }, {
                text: OpenLayers.i18n("images"),
                nodeType: "gx_layer",
                layer: this.layers["images"],
                iconCls: "picto_images",
                leaf: true
            }, {
                text: OpenLayers.i18n("products"),
                nodeType: "gx_layer",
                layer: this.layers["products"],
                iconCls: "picto_products",
                leaf: true
            }, {
                text: OpenLayers.i18n("outings"),
                nodeType: "gx_layer",
                layer: this.layers["outings"],
                iconCls: "picto_outings",
                leaf: true
            }, {
                text: OpenLayers.i18n("maps"),
                nodeType: "gx_layer",
                layer: this.layers["maps"],
                iconCls: "picto_maps",
                leaf: true
            }, {
                text: OpenLayers.i18n("areas"),
                expanded: false,
                iconCls: "picto_areas",
                children: [{
                    text: OpenLayers.i18n("ranges"),
                    nodeType: "gx_layer",
                    layer: this.layers["ranges"],
                    iconCls: "picto_blank",
                    leaf: true
                }, {
                    text: OpenLayers.i18n("admin boundaries"),
                    nodeType: "gx_layer",
                    layer: this.layers["admin_limits"],
                    iconCls: "picto_blank",
                    leaf: true
                }, {
                    text: OpenLayers.i18n("countries"),
                    nodeType: "gx_layer",
                    layer: this.layers["countries"],
                    iconCls: "picto_blank",
                    leaf: true
                }]
            }]
        }];
    },

    /** api: method[applyState]
     *  :arg state: ``Object``
     */
    applyState: function(state) {
        // actual state is loaded later in delayedApplyState to prevent
        // the layer from being displayed under the baselayers
        this.initialState = state;
    },

    /** private: method[delayedApplyState]
     */
    delayedApplyState: function() {
        if (this.initialState && this.initialState.layers) {
            this.initialThemes = Ext.isArray(this.initialState.layers)
                                 ? this.initialState.layers
                                 : [this.initialState.layers];
        }
    },

    getState: function() {
        var layers = [], state = {};
        for (var i in this.layers) {
            if (this.layers[i].getVisibility()) {
                layers.push(i);
            }
        }
        if (layers) {
            state["layers"] = layers.join(",");
        }
        return state;
    },

    loadInitialThemes: function() {
        var layers, map = this.mapPanel.map;
        for (var i = 0, len = this.initialThemes.length; i < len; i++) {
            layers = map.getLayersByName(this.initialThemes[i]);
            if (layers.length == 1) {
                layers[0].setVisibility(true);
            }
        }
    },

    makeThemesInteractive: function() {
        var layers = [];
        for (var name in this.layers) {
            layers.push(this.layers[name]);
        }
        var clickControl = new OpenLayers.Control.SelectFeature(
            layers, {
                clickout: true,
                onSelect: function(feature) {
                    var popup = new GeoExt.Popup({
                        width: 440,
                        height: 200,
                        autoScroll: true,
                        cls: "popup_content",
                        location: feature
                    });
                    popup.show();
                    var popupUrl = "/" + feature.data.module + "/popup/" + feature.data.id + "/raw/true";
                    popup.load({
                        url: popupUrl,
                        timeout: 60,
                        text: OpenLayers.i18n("Please wait...")
                    });
                },
                scope: this
            });

        var hoverControl = new c2corg.control.hoverFeature(layers, {});

        this.mapPanel.map.addControl(hoverControl);
        this.mapPanel.map.addControl(clickControl);

        hoverControl.activate();
        clickControl.activate();
    }
});

Ext.reg("c2corg_layertree", c2corg.tree.LayerTree);

Ext.namespace("c2corg.control");

c2corg.control.hoverFeature = OpenLayers.Class(OpenLayers.Control.SelectFeature, {
    hover: true,
    highlightOnly: true,
    renderIntent: "temporary",
    protocol: null,
    listening: true,

    initialize: function(layers, options) {
        OpenLayers.Control.SelectFeature.prototype.initialize.apply(this, [layers, options]);

        this.protocol = new OpenLayers.Protocol.HTTP({
            url: "/documents/tooltipPreview",
            format: new OpenLayers.Format.JSON(),
            params: {}
        });

        this.events.on({
            //beforefeaturehighlighted: this.report,
            featurehighlighted: this.showPreview,
            featureunhighlighted: this.hidePreview,
            scope: this
        });
    },

    showPreview: function(e) {
        if (!this.listening) {
            return;
        }
        this.listening = false;
        var feature = e.feature;
        this.currentFeature = feature;
        this.protocol.read({
            params: {
                module: feature.data.module,
                id: feature.data.id
            },
            callback: function(result) {
                if (result.success()) {
                    if (this.currentFeature.geometry instanceof OpenLayers.Geometry.Point) {
                        var lonlat = new OpenLayers.LonLat(this.currentFeature.geometry.x,
                                                           this.currentFeature.geometry.y);
                    } else {
                        // FIXME: would be better to use the cursor position
                        var lonlat = this.currentFeature.bounds.getCenterLonLat();
                    }
                    var px = this.map.getViewPortPxFromLonLat(lonlat);
                    this.div.innerHTML = OpenLayers.i18n("${item}. Click to show info", {
                        item: result.features.name
                    });
                    this.div.style.top = (px.y + 10) + "px";
                    this.div.style.left = (px.x + 10) + "px";
                    this.div.style.display = "block";
                }
            },
            scope: this
        });
    },

    hidePreview: function(e) {
        this.div.innerHTML = "";
        this.div.style.display = "none";
        this.listening = true;
    },

    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this, arguments);
        this.div.className = "tooltip_tooltip";
        this.div.style.display = "none";
        return this.div;
    }
});
<commit_msg>ensure that c2c layers window will not go out of the map on the right when shrinking the page witdh<commit_after>/*
 * @requires plugins/Tool.js
 * @requires OpenLayers/Request.js
 * @include OpenLayers/Layer/Vector.js
 * @include OpenLayers/Strategy/BBOX.js
 * @include OpenLayers/Protocol/WFS/v1_0_0.js
 * @include OpenLayers/Protocol/WFS.js
 * @include OpenLayers/Protocol/HTTP.js
 * @include OpenLayers/Format/JSON.js
 * @include OpenLayers/Control/SelectFeature.js
 * @include GeoExt/widgets/tree/LayerNode.js
 * @include styles.js
 */

Ext.namespace("c2corg.plugins");

c2corg.plugins.LayerTree = Ext.extend(gxp.plugins.Tool, {

    ptype: "c2corg_layertree",

    init: function() {
        c2corg.plugins.LayerTree.superclass.init.apply(this, arguments);
        this.target.on("ready", this.viewerReady, this);
    },

    viewerReady: function() {
        this.tree.delayedApplyState();
        this.tree.loadInitialThemes();
        this.tree.makeThemesInteractive();

        // listen on window resize to be sure that the
        // window won't go out of the map
        Ext.select(window).on("resize", function() {
            var w = this.tree.findParentByType("window");
            var m = this.target.mapPanel.getEl();
            var xy = w.el.getAlignToXY(m, "tr-tr", [-5, 0]);
            var pos = w.getPosition();

            if (xy[0] <= pos[0]) {
                w.alignTo(m, "tr-tr", [-20, pos[1]-xy[1]]);
            }
        }, this);
    },

    addOutput: function(config) {

        config = Ext.apply({
            xtype: "c2corg_layertree",
            mapPanel: this.target.mapPanel,
            url: this.url,
            initialThemes: this.initialThemes || []
        }, config || {});

        this.tree = c2corg.plugins.LayerTree.superclass.addOutput.call(this, config);
        this.tree.findParentByType("window").alignTo(this.target.mapPanel.getEl(), "tr-tr", [-20, 45]);
        return this.tree;
    }
});

Ext.preg(c2corg.plugins.LayerTree.prototype.ptype, c2corg.plugins.LayerTree);

Ext.namespace("c2corg.tree");

c2corg.tree.LayerTree = Ext.extend(Ext.tree.TreePanel, {

    baseCls: "layertree",
    enableDD: false,
    rootVisible: false,
    useArrows: true,

    mapPanel: null,
    initialState: null,
    initialThemes: null,

    stateEvents: ["layervisibilitychange"],
    stateId: "tree",

    url: null,
    layers: {},
    styleMap: null,

    initComponent: function() {
        this.addLayers();
        this.root = {
            children: this.getThemes()
        };
        c2corg.tree.LayerTree.superclass.initComponent.call(this, arguments);

        this.addEvents(
            /** private: event[layervisibilitychange]
             *  Fires after a checkbox state changes
             */
            "layervisibilitychange"
        );
        this.on("checkchange", function(node, checked) {
            this.fireEvent("layervisibilitychange");
        }, this);
    },

    getStyleMap: function() {
        if (!this.styleMap) {
            this.styleMap = c2corg.styleMap();
        }
        return this.styleMap;
    },

    createVectorLayer: function(options) {
        return new OpenLayers.Layer.Vector(options.name, {
            strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1, ratio: 1})],
            protocol: new OpenLayers.Protocol.WFS({
                featureType: options.featureType,
                url: this.url,
                maxFeatures: options.maxFeatures || 200,
                geometryName: "geom",
                srsName: "EPSG:900913"
            }),
            isBaseLayer: false,
            visibility: false,
            styleMap: this.getStyleMap()
        });
    },

    addLayers: function() {
        this.layers = {
            "summits": this.createVectorLayer({name: "summits", featureType: "summits"}),
            "access": this.createVectorLayer({name: "access", featureType: "access"}),
            "huts": this.createVectorLayer({name: "huts", featureType: "huts"}),
            "sites": this.createVectorLayer({name: "sites", featureType: "sites"}),
            "users": this.createVectorLayer({name: "users", featureType: "users"}),
            "images": this.createVectorLayer({name: "images", featureType: "images"}),
            "products": this.createVectorLayer({name: "products", featureType: "products"}),
            "routes": this.createVectorLayer({name: "routes", featureType: "routes", maxFeatures: 50}),
            "outings": this.createVectorLayer({name: "outings", featureType: "outings", maxFeatures: 50}),
            "maps": this.createVectorLayer({name: "maps", featureType: "maps"}),
            "ranges": this.createVectorLayer({name: "ranges", featureType: "ranges"}),
            "admin_limits": this.createVectorLayer({name: "admin_limits", featureType: "admin_limits"}),
            "countries": this.createVectorLayer({name: "countries", featureType: "countries"})
        };
        for (var i in this.layers) {
            this.mapPanel.map.addLayer(this.layers[i]);
        }
    },

    getThemes: function() {
        return [{
            text: OpenLayers.i18n("summits"),
            nodeType: "gx_layer",
            layer: this.layers["summits"],
            iconCls: "picto_summits",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("pass"),
                iconCls: "picto_pass",
                leaf: true
            },{
                text: OpenLayers.i18n("lake"),
                iconCls: "picto_lake",
                leaf: true
            },{
                text: OpenLayers.i18n("valley"),
                iconCls: "picto_crag",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("parkings"),
            nodeType: "gx_layer",
            layer: this.layers["access"],
            iconCls: "picto_parkings",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("public_transportations"),
                iconCls: "picto_parking_green",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("huts"),
            nodeType: "gx_layer",
            layer: this.layers["huts"],
            iconCls: "picto_huts",
            expanded: false,
            children: [{
                text: OpenLayers.i18n("gite"),
                iconCls: "picto_gite",
                leaf: true
            }, {
                text: OpenLayers.i18n("camping area"),
                iconCls: "picto_camp",
                leaf: true
            }]
        }, {
            text: OpenLayers.i18n("sites"),
            nodeType: "gx_layer",
            layer: this.layers["sites"],
            iconCls: "picto_sites",
            leaf: true
        }, {
            text: OpenLayers.i18n("routes"),
            nodeType: "gx_layer",
            layer: this.layers["routes"],
            iconCls: "picto_routes",
            leaf: true
        }, {
            text: OpenLayers.i18n("More..."),
            expanded: false,
            children: [{
                text: OpenLayers.i18n("users"),
                nodeType: "gx_layer",
                layer: this.layers["users"],
                iconCls: "picto_users",
                leaf: true
            }, {
                text: OpenLayers.i18n("images"),
                nodeType: "gx_layer",
                layer: this.layers["images"],
                iconCls: "picto_images",
                leaf: true
            }, {
                text: OpenLayers.i18n("products"),
                nodeType: "gx_layer",
                layer: this.layers["products"],
                iconCls: "picto_products",
                leaf: true
            }, {
                text: OpenLayers.i18n("outings"),
                nodeType: "gx_layer",
                layer: this.layers["outings"],
                iconCls: "picto_outings",
                leaf: true
            }, {
                text: OpenLayers.i18n("maps"),
                nodeType: "gx_layer",
                layer: this.layers["maps"],
                iconCls: "picto_maps",
                leaf: true
            }, {
                text: OpenLayers.i18n("areas"),
                expanded: false,
                iconCls: "picto_areas",
                children: [{
                    text: OpenLayers.i18n("ranges"),
                    nodeType: "gx_layer",
                    layer: this.layers["ranges"],
                    iconCls: "picto_blank",
                    leaf: true
                }, {
                    text: OpenLayers.i18n("admin boundaries"),
                    nodeType: "gx_layer",
                    layer: this.layers["admin_limits"],
                    iconCls: "picto_blank",
                    leaf: true
                }, {
                    text: OpenLayers.i18n("countries"),
                    nodeType: "gx_layer",
                    layer: this.layers["countries"],
                    iconCls: "picto_blank",
                    leaf: true
                }]
            }]
        }];
    },

    /** api: method[applyState]
     *  :arg state: ``Object``
     */
    applyState: function(state) {
        // actual state is loaded later in delayedApplyState to prevent
        // the layer from being displayed under the baselayers
        this.initialState = state;
    },

    /** private: method[delayedApplyState]
     */
    delayedApplyState: function() {
        if (this.initialState && this.initialState.layers) {
            this.initialThemes = Ext.isArray(this.initialState.layers)
                                 ? this.initialState.layers
                                 : [this.initialState.layers];
        }
    },

    getState: function() {
        var layers = [], state = {};
        for (var i in this.layers) {
            if (this.layers[i].getVisibility()) {
                layers.push(i);
            }
        }
        if (layers) {
            state["layers"] = layers.join(",");
        }
        return state;
    },

    loadInitialThemes: function() {
        var layers, map = this.mapPanel.map;
        for (var i = 0, len = this.initialThemes.length; i < len; i++) {
            layers = map.getLayersByName(this.initialThemes[i]);
            if (layers.length == 1) {
                layers[0].setVisibility(true);
            }
        }
    },

    makeThemesInteractive: function() {
        var layers = [];
        for (var name in this.layers) {
            layers.push(this.layers[name]);
        }
        var clickControl = new OpenLayers.Control.SelectFeature(
            layers, {
                clickout: true,
                onSelect: function(feature) {
                    var popup = new GeoExt.Popup({
                        width: 440,
                        height: 200,
                        autoScroll: true,
                        cls: "popup_content",
                        location: feature
                    });
                    popup.show();
                    var popupUrl = "/" + feature.data.module + "/popup/" + feature.data.id + "/raw/true";
                    popup.load({
                        url: popupUrl,
                        timeout: 60,
                        text: OpenLayers.i18n("Please wait...")
                    });
                },
                scope: this
            });

        var hoverControl = new c2corg.control.hoverFeature(layers, {});

        this.mapPanel.map.addControl(hoverControl);
        this.mapPanel.map.addControl(clickControl);

        hoverControl.activate();
        clickControl.activate();
    }
});

Ext.reg("c2corg_layertree", c2corg.tree.LayerTree);

Ext.namespace("c2corg.control");

c2corg.control.hoverFeature = OpenLayers.Class(OpenLayers.Control.SelectFeature, {
    hover: true,
    highlightOnly: true,
    renderIntent: "temporary",
    protocol: null,
    listening: true,

    initialize: function(layers, options) {
        OpenLayers.Control.SelectFeature.prototype.initialize.apply(this, [layers, options]);

        this.protocol = new OpenLayers.Protocol.HTTP({
            url: "/documents/tooltipPreview",
            format: new OpenLayers.Format.JSON(),
            params: {}
        });

        this.events.on({
            //beforefeaturehighlighted: this.report,
            featurehighlighted: this.showPreview,
            featureunhighlighted: this.hidePreview,
            scope: this
        });
    },

    showPreview: function(e) {
        if (!this.listening) {
            return;
        }
        this.listening = false;
        var feature = e.feature;
        this.currentFeature = feature;
        this.protocol.read({
            params: {
                module: feature.data.module,
                id: feature.data.id
            },
            callback: function(result) {
                if (result.success()) {
                    if (this.currentFeature.geometry instanceof OpenLayers.Geometry.Point) {
                        var lonlat = new OpenLayers.LonLat(this.currentFeature.geometry.x,
                                                           this.currentFeature.geometry.y);
                    } else {
                        // FIXME: would be better to use the cursor position
                        var lonlat = this.currentFeature.bounds.getCenterLonLat();
                    }
                    var px = this.map.getViewPortPxFromLonLat(lonlat);
                    this.div.innerHTML = OpenLayers.i18n("${item}. Click to show info", {
                        item: result.features.name
                    });
                    this.div.style.top = (px.y + 10) + "px";
                    this.div.style.left = (px.x + 10) + "px";
                    this.div.style.display = "block";
                }
            },
            scope: this
        });
    },

    hidePreview: function(e) {
        this.div.innerHTML = "";
        this.div.style.display = "none";
        this.listening = true;
    },

    draw: function() {
        OpenLayers.Control.prototype.draw.apply(this, arguments);
        this.div.className = "tooltip_tooltip";
        this.div.style.display = "none";
        return this.div;
    }
});
<|endoftext|>