<commit_before>/* eslint-disable react/no-danger */

import React from 'react';
import Helmet from 'react-helmet';
import serialize from 'serialize-javascript';
import _ from 'lodash';

import type { Store } from '../types';

type Props = { store: Store, htmlContent: string };

const Html = ({ store, htmlContent }: Props) => {
  // Should be declared after "renderToStaticMarkup()" of "../server.js" or it won't work
  const head = Helmet.renderStatic();
  const attrs = head.htmlAttributes.toComponent();
  const { lang, ...rest } = attrs || {};
  const assets = webpackIsomorphicTools.assets();

  return (
    <html {...rest} lang={lang || 'en'}>
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="x-ua-compatible" content="ie=edge" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        <link rel="apple-touch-icon" href="apple-touch-icon.png" />
        <link rel="shortcut icon" href="/favicon.ico" />

        {head.title.toComponent()}
        {head.base.toComponent()}
        {head.meta.toComponent()}
        {head.link.toComponent()}

        {/* Rendering bundled styles into <link> tag on production */}
        {_.keys(assets.styles).map(style => (
          <link
            key={_.uniqueId()}
            href={assets.styles[style]}
            media="screen, projection"
            rel="stylesheet"
            type="text/css"
          />
        ))}
        {/* Rendering bundled styles into <style> tag on development */}
        {/* I put all of the styles here to smoothen the flick */}
        {_.keys(assets.styles).length === 0 ? (
          <style
            dangerouslySetInnerHTML={{
              __html:
                require('../theme/normalize.css')._style +
                require('../containers/App/styles.scss')._style +
                require('../containers/Home/styles.scss')._style +
                require('../containers/UserInfo/styles.scss')._style +
                require('../containers/NotFound/styles.scss')._style +
                require('../components/UserList/styles.scss')._style +
                require('../components/UserCard/styles.scss')._style
            }}
          />
        ) : null}
      </head>
      <body>
        <div
          id="react-view"
          // Rendering the route, which passed from server-side
          dangerouslySetInnerHTML={{ __html: htmlContent }}
        />

        <script
          // Storing the initial state into window
          dangerouslySetInnerHTML={{
            __html:
              store &&
              `window.__INITIAL_STATE__=${serialize(store.getState())};`
          }}
        />
        {/* Rendering bundled scripts into <script> tag */}
        {_.map(assets.javascript, script => (
          <script key={_.uniqueId()} src={assets.javascript[script]} />
        ))}
        {head.script.toComponent()}
      </body>
    </html>
  );
};

export default Html;
<commit_msg>Fixing react-hot-loader<commit_after>/* eslint-disable react/no-danger */

import React from 'react';
import Helmet from 'react-helmet';
import serialize from 'serialize-javascript';
import _ from 'lodash';

import type { Store } from '../types';

type Props = { store: Store, htmlContent: string };

const Html = ({ store, htmlContent }: Props) => {
  // Should be declared after "renderToStaticMarkup()" of "../server.js" or it won't work
  const head = Helmet.renderStatic();
  const attrs = head.htmlAttributes.toComponent();
  const { lang, ...rest } = attrs || {};
  const assets = webpackIsomorphicTools.assets();

  return (
    <html {...rest} lang={lang || 'en'}>
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="x-ua-compatible" content="ie=edge" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        <link rel="apple-touch-icon" href="apple-touch-icon.png" />
        <link rel="shortcut icon" href="/favicon.ico" />

        {head.title.toComponent()}
        {head.base.toComponent()}
        {head.meta.toComponent()}
        {head.link.toComponent()}

        {/* Rendering bundled styles into <link> tag on production */}
        {_.keys(assets.styles).map(style => (
          <link
            key={_.uniqueId()}
            href={assets.styles[style]}
            media="screen, projection"
            rel="stylesheet"
            type="text/css"
          />
        ))}
        {/* Rendering bundled styles into <style> tag on development */}
        {/* I put all of the styles here to smoothen the flick */}
        {_.keys(assets.styles).length === 0 ? (
          <style
            dangerouslySetInnerHTML={{
              __html:
                require('../theme/normalize.css')._style +
                require('../containers/App/styles.scss')._style +
                require('../containers/Home/styles.scss')._style +
                require('../containers/UserInfo/styles.scss')._style +
                require('../containers/NotFound/styles.scss')._style +
                require('../components/UserList/styles.scss')._style +
                require('../components/UserCard/styles.scss')._style
            }}
          />
        ) : null}
      </head>
      <body>
        <div
          id="react-view"
          // Rendering the route, which passed from server-side
          dangerouslySetInnerHTML={{ __html: htmlContent }}
        />

        <script
          // Storing the initial state into window
          dangerouslySetInnerHTML={{
            __html:
              store &&
              `window.__INITIAL_STATE__=${serialize(store.getState())};`
          }}
        />
        {/* Rendering bundled scripts into <script> tag */}
        {_.keys(assets.javascript).map(script => (
          <script key={_.uniqueId()} src={assets.javascript[script]} />
        ))}
        {head.script.toComponent()}
      </body>
    </html>
  );
};

export default Html;
<|endoftext|>


<commit_before>// @flow

import * as React from 'react';
import { View } from 'react-native';
import idx from 'idx';
import { createFragmentContainer, graphql } from 'react-relay';
import {
  StyleSheet,
  Color,
  AdaptableBadge,
  Text,
  Touchable,
} from '@kiwicom/react-native-app-shared';
import Translation, {
  DummyTranslation,
  TranslationFragment,
} from '@kiwicom/react-native-app-translations';

import type { Facilities_facilities } from './__generated__/Facilities_facilities.graphql';

const styles = StyleSheet.create({
  facilities: {
    marginTop: 15,
    paddingTop: 15,
    borderTopWidth: 1,
    borderTopColor: Color.grey.$200,
    flexWrap: 'wrap',
    alignItems: 'flex-start',
    flexDirection: 'row',
  },
  lessMoreButton: {
    color: Color.brand,
    fontWeight: '800',
  },
  adaptableBadge: {
    backgroundColor: Color.blueGrey.$50,
    marginRight: 5,
    marginBottom: 5,
  },
  adaptableBadgeText: {
    color: Color.textLight,
  },
});

type ContainerProps = {|
  facilities: any,
|};

type Props = {
  ...ContainerProps,
  facilities: ?Facilities_facilities,
};

type State = {|
  collapsed: boolean,
|};

export class Facilities extends React.Component<Props, State> {
  state = {
    collapsed: true,
  };

  toggle = () => {
    this.setState(({ collapsed }) => ({
      collapsed: !collapsed,
    }));
  };

  render() {
    const { facilities } = this.props;
    const { collapsed } = this.state;
    const edges = idx(facilities, _ => _.edges) || [];
    const fullList = edges.map(edge => idx(edge, _ => _.node));
    const shortlist = fullList.slice(0, 9);
    const listToRender = collapsed ? shortlist : fullList;

    return (
      <View style={styles.facilities}>
        {listToRender.map(facility => {
          return (
            facility && (
              <AdaptableBadge
                key={facility.id}
                text={facility.name || ''}
                style={styles.adaptableBadge}
                textStyle={styles.adaptableBadgeText}
              />
            )
          );
        })}
        {fullList.length > shortlist.length && (
          <Touchable onPress={this.toggle}>
            <Text style={styles.lessMoreButton}>
              {collapsed ? (
                <TranslationFragment>
                  <DummyTranslation
                    id={`+${fullList.length - shortlist.length} `}
                  />
                  <Translation id="SingleHotel.Description.Facilities.ShowMore" />
                </TranslationFragment>
              ) : (
                <Translation id="SingleHotel.Description.Facilities.ShowLess" />
              )}
            </Text>
          </Touchable>
        )}
      </View>
    );
  }
}

export default (createFragmentContainer(
  Facilities,
  graphql`
    fragment Facilities_facilities on HotelFacilityConnection {
      edges {
        node {
          id
          name
        }
      }
    }
  `,
): React.ComponentType<ContainerProps>);
<commit_msg>Hotel facilities: do not use ripple effect for link buttons<commit_after>// @flow

import * as React from 'react';
import { View } from 'react-native';
import idx from 'idx';
import { createFragmentContainer, graphql } from 'react-relay';
import {
  StyleSheet,
  Color,
  AdaptableBadge,
  Text,
  Touchable,
} from '@kiwicom/react-native-app-shared';
import Translation, {
  DummyTranslation,
  TranslationFragment,
} from '@kiwicom/react-native-app-translations';

import type { Facilities_facilities } from './__generated__/Facilities_facilities.graphql';

const styles = StyleSheet.create({
  facilities: {
    marginTop: 15,
    paddingTop: 15,
    borderTopWidth: 1,
    borderTopColor: Color.grey.$200,
    flexWrap: 'wrap',
    alignItems: 'flex-start',
    flexDirection: 'row',
  },
  lessMoreButton: {
    color: Color.brand,
    fontWeight: '800',
  },
  adaptableBadge: {
    backgroundColor: Color.blueGrey.$50,
    marginRight: 5,
    marginBottom: 5,
  },
  adaptableBadgeText: {
    color: Color.textLight,
  },
});

type ContainerProps = {|
  facilities: any,
|};

type Props = {
  ...ContainerProps,
  facilities: ?Facilities_facilities,
};

type State = {|
  collapsed: boolean,
|};

export class Facilities extends React.Component<Props, State> {
  state = {
    collapsed: true,
  };

  toggle = () => {
    this.setState(({ collapsed }) => ({
      collapsed: !collapsed,
    }));
  };

  render() {
    const { facilities } = this.props;
    const { collapsed } = this.state;
    const edges = idx(facilities, _ => _.edges) || [];
    const fullList = edges.map(edge => idx(edge, _ => _.node));
    const shortlist = fullList.slice(0, 9);
    const listToRender = collapsed ? shortlist : fullList;

    return (
      <View style={styles.facilities}>
        {listToRender.map(facility => {
          return (
            facility && (
              <AdaptableBadge
                key={facility.id}
                text={facility.name || ''}
                style={styles.adaptableBadge}
                textStyle={styles.adaptableBadgeText}
              />
            )
          );
        })}
        {fullList.length > shortlist.length && (
          <Touchable onPress={this.toggle} noRipple={true}>
            <Text style={styles.lessMoreButton}>
              {collapsed ? (
                <TranslationFragment>
                  <DummyTranslation
                    id={`+${fullList.length - shortlist.length} `}
                  />
                  <Translation id="SingleHotel.Description.Facilities.ShowMore" />
                </TranslationFragment>
              ) : (
                <Translation id="SingleHotel.Description.Facilities.ShowLess" />
              )}
            </Text>
          </Touchable>
        )}
      </View>
    );
  }
}

export default (createFragmentContainer(
  Facilities,
  graphql`
    fragment Facilities_facilities on HotelFacilityConnection {
      edges {
        node {
          id
          name
        }
      }
    }
  `,
): React.ComponentType<ContainerProps>);
<|endoftext|>


<commit_before>import path from 'path';
import mkdirp from 'mkdirp';
import { cloneOrFetchRepo, cloneRepo, checkoutSha, getWorkdirForRepoUrl,
  getTempdirForRepoUrl, getOriginForRepo, getHeadForRepo } from './git-api';
import { getSanitizedRepoUrl, getNwoFromRepoUrl, postCommitStatus, createGist,
  findPRForCommit } from './github-api';
import { determineBuildCommands, runAllBuildCommands, uploadBuildArtifacts } from './build-api';
import { fs, rimraf } from './promisify';
import { retryPromise } from './promise-array';

const d = require('debug')('surf:surf-build');

function getRootAppDir() {
  let ret = null;

  switch (process.platform) {
  case 'win32':
    ret = path.join(process.env.LOCALAPPDATA, 'surf');
    break;
  case 'darwin':
    ret = path.join(process.env.HOME, 'Library', 'Application Support', 'surf');
    break;
  default:
    ret = path.join(process.env.HOME, '.config', 'surf');
    break;
  }

  mkdirp.sync(ret);
  return ret;
}

function getRepoCloneDir() {
  return path.join(getRootAppDir(), 'repos');
}

export default function main(argv, showHelp) {
  return realMain(argv, showHelp)
    .then(() => Promise.resolve(true), (e) => {
      if (argv.name) {
        let repo = argv.repo || process.env.SURF_REPO;
        let sha = argv.sha || process.env.SURF_SHA1;
        let nwo = getNwoFromRepoUrl(repo);

        return retryPromise(() =>
            postCommitStatus(nwo, sha, 'error', 'Surf Build Server', null, argv.name))
          .catch(() => true)
          .then(() => Promise.reject(e));
      } else {
        return Promise.reject(e);
      }
    });
}

async function realMain(argv, showHelp) {
  let sha = argv.sha || process.env.SURF_SHA1;
  let repo = argv.repo || process.env.SURF_REPO;
  let nwo = getNwoFromRepoUrl(repo);
  let name = argv.name;

  // If the current PR number isn't set, try to recreate it
  process.env.SURF_NWO = nwo;
  if (!process.env.SURF_PR_NUM) {
    let pr = await findPRForCommit(nwo, sha);

    if (pr) {
      process.env.SURF_PR_NUM = pr.number;
      process.env.SURF_REF = pr.head.ref;
    }
  }

  if (argv.help) {
    showHelp();
    process.exit(0);
  }

  if (name === '__test__') {
    // NB: Don't end up setting statuses in unit tests, even if argv.name is set
    name = null;
  }

  let setRepoViaPwd = false;
  if (!repo) {
    try {
      repo = getSanitizedRepoUrl(await getOriginForRepo('.'));
      argv.repo = repo;
      setRepoViaPwd = true;
    } catch (e) {
      console.error("Repository not specified and current directory is not a Git repo");
      d(e.stack);

      showHelp();
      process.exit(-1);
    }
  }

  if (!repo) {
    showHelp();
    process.exit(-1);
  }

  let repoDir = getRepoCloneDir();

  d(`Running initial cloneOrFetchRepo: ${repo} => ${repoDir}`);
  let bareRepoDir = await retryPromise(() => cloneOrFetchRepo(repo, repoDir));

  if (!sha) {
    try {
      sha = await getHeadForRepo(setRepoViaPwd ? '.' : bareRepoDir);
      argv.sha = sha;
    } catch (e) {
      console.error(`Failed to find the current commit for repo ${repo}: ${e.message}`);
      d(e.stack);

      showHelp();
      process.exit(-1);
    }
  }

  d(`repo: ${repo}, sha: ${sha}`);

  if (name) {
    d(`Posting 'pending' to GitHub status`);

    let nwo = getNwoFromRepoUrl(repo);
    await retryPromise(() =>
      postCommitStatus(nwo, sha, 'pending', 'Surf Build Server', null, name));
  }

  let workDir = getWorkdirForRepoUrl(repo, sha);
  let tempDir = getTempdirForRepoUrl(repo, sha);

  d(`Cloning to work directory: ${workDir}`);
  let r = await retryPromise(() => cloneRepo(bareRepoDir, workDir, null, false));
  r.free();

  d(`Checking out to given SHA1: ${sha}`);
  await checkoutSha(workDir, sha);

  d(`Determining command to build`);
  let { cmd, cmds, args, artifactDirs } = await determineBuildCommands(workDir);

  if (!cmds) {
    cmds = [{cmd, args}];
  }

  let buildPassed = false;
  let buildOutput = null;

  try {
    let buildStream = runAllBuildCommands(cmds, workDir, sha, tempDir);

    buildOutput = '';
    buildStream.subscribe((x) => {
      buildOutput += x;
      console.log(x.replace(/[\r\n]+$/, ''));
    }, () => {});

    await buildStream
      .reduce(() => null)
      .toPromise();

    buildPassed = true;
  } catch (e) {
    buildOutput += `\n${e.message}`;

    console.log(`\nError during build: ${e.message}`);
    d(e.stack);
  }

  await fs.writeFile(path.join(workDir, 'build-output.log'), buildOutput);

  if (name) {
    d(`Posting 'success' to GitHub status`);

    let gistInfo = await retryPromise(() => createGist(`Build completed: ${nwo}#${sha}, ${new Date()}`, {
      "build-output.txt": {
        content: buildOutput
      }
    }));

    d(`Gist result: ${gistInfo.result.html_url}`);
    d(`Gist clone URL: ${gistInfo.result.git_pull_url}`);
    if (buildPassed) {
      let token = process.env.GIST_TOKEN || process.env.GITHUB_TOKEN;

      try {
        d(`Uploading build artifacts using token: ${token}`);
        let targetDir = await retryPromise(() => uploadBuildArtifacts(gistInfo.result.id, gistInfo.result.git_pull_url, artifactDirs, token));
        await rimraf(targetDir);
      } catch (e) {
        console.error(`Failed to upload build artifacts: ${e.message}`);
        d(e.stack);
      }
    }

    let nwo = getNwoFromRepoUrl(repo);
    await postCommitStatus(nwo, sha,
      buildPassed ? 'success' : 'failure', 'Surf Build Server', gistInfo.result.html_url, name);
  }

  if (buildPassed) {
    await rimraf(tempDir);
  }
}
<commit_msg>Set the build name as an env var if we're posting build statuses<commit_after>import path from 'path';
import mkdirp from 'mkdirp';
import { cloneOrFetchRepo, cloneRepo, checkoutSha, getWorkdirForRepoUrl,
  getTempdirForRepoUrl, getOriginForRepo, getHeadForRepo } from './git-api';
import { getSanitizedRepoUrl, getNwoFromRepoUrl, postCommitStatus, createGist,
  findPRForCommit } from './github-api';
import { determineBuildCommands, runAllBuildCommands, uploadBuildArtifacts } from './build-api';
import { fs, rimraf } from './promisify';
import { retryPromise } from './promise-array';

const d = require('debug')('surf:surf-build');

function getRootAppDir() {
  let ret = null;

  switch (process.platform) {
  case 'win32':
    ret = path.join(process.env.LOCALAPPDATA, 'surf');
    break;
  case 'darwin':
    ret = path.join(process.env.HOME, 'Library', 'Application Support', 'surf');
    break;
  default:
    ret = path.join(process.env.HOME, '.config', 'surf');
    break;
  }

  mkdirp.sync(ret);
  return ret;
}

function getRepoCloneDir() {
  return path.join(getRootAppDir(), 'repos');
}

export default function main(argv, showHelp) {
  return realMain(argv, showHelp)
    .then(() => Promise.resolve(true), (e) => {
      if (argv.name) {
        let repo = argv.repo || process.env.SURF_REPO;
        let sha = argv.sha || process.env.SURF_SHA1;
        let nwo = getNwoFromRepoUrl(repo);

        return retryPromise(() =>
            postCommitStatus(nwo, sha, 'error', 'Surf Build Server', null, argv.name))
          .catch(() => true)
          .then(() => Promise.reject(e));
      } else {
        return Promise.reject(e);
      }
    });
}

async function configureEnvironmentVariablesForChild(nwo, sha, name) {
  process.env.SURF_NWO = nwo;
  if (name) process.env.SURF_BUILD_NAME = name;

  // If the current PR number isn't set, try to recreate it
  if (!process.env.SURF_PR_NUM) {
    let pr = await findPRForCommit(nwo, sha);

    if (pr) {
      process.env.SURF_PR_NUM = pr.number;
      process.env.SURF_REF = pr.head.ref;
    }
  }
}

async function realMain(argv, showHelp) {
  let sha = argv.sha || process.env.SURF_SHA1;
  let repo = argv.repo || process.env.SURF_REPO;
  let nwo = getNwoFromRepoUrl(repo);
  let name = argv.name;

  if (argv.help) {
    showHelp();
    process.exit(0);
  }

  await configureEnvironmentVariablesForChild(nwo, sha, name);

  if (name === '__test__') {
    // NB: Don't end up setting statuses in unit tests, even if argv.name is set
    name = null;
  }

  let setRepoViaPwd = false;
  if (!repo) {
    try {
      repo = getSanitizedRepoUrl(await getOriginForRepo('.'));
      argv.repo = repo;
      setRepoViaPwd = true;
    } catch (e) {
      console.error("Repository not specified and current directory is not a Git repo");
      d(e.stack);

      showHelp();
      process.exit(-1);
    }
  }

  if (!repo) {
    showHelp();
    process.exit(-1);
  }

  let repoDir = getRepoCloneDir();

  d(`Running initial cloneOrFetchRepo: ${repo} => ${repoDir}`);
  let bareRepoDir = await retryPromise(() => cloneOrFetchRepo(repo, repoDir));

  if (!sha) {
    try {
      sha = await getHeadForRepo(setRepoViaPwd ? '.' : bareRepoDir);
      argv.sha = sha;
    } catch (e) {
      console.error(`Failed to find the current commit for repo ${repo}: ${e.message}`);
      d(e.stack);

      showHelp();
      process.exit(-1);
    }
  }

  d(`repo: ${repo}, sha: ${sha}`);

  if (name) {
    d(`Posting 'pending' to GitHub status`);

    let nwo = getNwoFromRepoUrl(repo);
    await retryPromise(() =>
      postCommitStatus(nwo, sha, 'pending', 'Surf Build Server', null, name));
  }

  let workDir = getWorkdirForRepoUrl(repo, sha);
  let tempDir = getTempdirForRepoUrl(repo, sha);

  d(`Cloning to work directory: ${workDir}`);
  let r = await retryPromise(() => cloneRepo(bareRepoDir, workDir, null, false));
  r.free();

  d(`Checking out to given SHA1: ${sha}`);
  await checkoutSha(workDir, sha);

  d(`Determining command to build`);
  let { cmd, cmds, args, artifactDirs } = await determineBuildCommands(workDir);

  if (!cmds) {
    cmds = [{cmd, args}];
  }

  let buildPassed = false;
  let buildOutput = null;

  try {
    let buildStream = runAllBuildCommands(cmds, workDir, sha, tempDir);

    buildOutput = '';
    buildStream.subscribe((x) => {
      buildOutput += x;
      console.log(x.replace(/[\r\n]+$/, ''));
    }, () => {});

    await buildStream
      .reduce(() => null)
      .toPromise();

    buildPassed = true;
  } catch (e) {
    buildOutput += `\n${e.message}`;

    console.log(`\nError during build: ${e.message}`);
    d(e.stack);
  }

  await fs.writeFile(path.join(workDir, 'build-output.log'), buildOutput);

  if (name) {
    d(`Posting 'success' to GitHub status`);

    let gistInfo = await retryPromise(() => createGist(`Build completed: ${nwo}#${sha}, ${new Date()}`, {
      "build-output.txt": {
        content: buildOutput
      }
    }));

    d(`Gist result: ${gistInfo.result.html_url}`);
    d(`Gist clone URL: ${gistInfo.result.git_pull_url}`);
    if (buildPassed) {
      let token = process.env.GIST_TOKEN || process.env.GITHUB_TOKEN;

      try {
        d(`Uploading build artifacts using token: ${token}`);
        let targetDir = await retryPromise(() => uploadBuildArtifacts(gistInfo.result.id, gistInfo.result.git_pull_url, artifactDirs, token));
        await rimraf(targetDir);
      } catch (e) {
        console.error(`Failed to upload build artifacts: ${e.message}`);
        d(e.stack);
      }
    }

    let nwo = getNwoFromRepoUrl(repo);
    await postCommitStatus(nwo, sha,
      buildPassed ? 'success' : 'failure', 'Surf Build Server', gistInfo.result.html_url, name);
  }

  if (buildPassed) {
    await rimraf(tempDir);
  }
}
<|endoftext|>


<commit_before>var express = require('express'),
  app = express(),
  fs = require('fs'),
  readline = require('readline'),
  CSV = require('csv-string'),
  filename = process.argv[2],
  lines = [];
//
//
//var rd = readline.createInterface({
//    input: fs.createReadStream(filename, {encoding: 'utf-8'}),
//    output: process.stdout,
//    terminal: false
//});
//
//rd.on('line', function(line) {
//    var splittedLine = line.split("\t");
//    var newLineJSON = {
//        'ip': splittedLine[0],
//        'city': splittedLine[1],
//        'country': splittedLine[2],
//        'latitude': splittedLine[3],
//        'longitude': splittedLine[4],
//        'date': splittedLine[5],
//        'request': splittedLine[6].replace(/"/g, ""),
//        'status_code': splittedLine[7],
//        'content_size': splittedLine[8]
//    };
//
//    lines.push(newLineJSON);
//});
//
//app.get('/data', function (req, res) {
//  var tenLines =[];
//  for(var i = 0; i < 10; i++) {
//      tenLines.push(lines[Math.floor(Math.random()*lines.length)]);
//  }
//  res.json(tenLines);
//});

app.get('/status', function (req, res) {
  res.json({"status": "ok"})
});

/**
 * Migrants API
 */

var dbfile = "";
var db = {};
var filename = 'data/migr_imm5prv_1_Data.csv'

var rd = readline.createInterface({
  input: fs.createReadStream(filename, {encoding: 'utf-8'}),
  output: process.stdout,
  terminal: false
});

rd.on('line', function(line) {
  if (line.indexOf('TIME') < 0) {
    dbfile += line +'\n';
  }
});

rd.on('pause', function() {
  data = CSV.parse(dbfile);
  for (var i = 0; i < data.length; i++ ) {
    var country = data[i][1];
    var year = data[i][0];
    var origin = data[i][2];
    var age = data[i][3];
    var gender = data[i][4];
    var value = data[i][6];

    if (country.length > 0 && year.length > 0) {
      if (! (country in db)) {
        db[country] = {};
      }

      if (age == 'TOTAL' && gender == 'Total' && value !== ':') {
        db[country][year] = value;
      }
    }
  }
  console.log("Data ready.", data.length);
})

app.get('/data/summary', function (req, res) {
  res.json(db);
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Example app listening at http://%s:%s', host, port);
});
<commit_msg>Add CORS headers<commit_after>var express = require('express'),
  app = express(),
  fs = require('fs'),
  readline = require('readline'),
  CSV = require('csv-string'),
  filename = process.argv[2],
  lines = [];
//
//
//var rd = readline.createInterface({
//    input: fs.createReadStream(filename, {encoding: 'utf-8'}),
//    output: process.stdout,
//    terminal: false
//});
//
//rd.on('line', function(line) {
//    var splittedLine = line.split("\t");
//    var newLineJSON = {
//        'ip': splittedLine[0],
//        'city': splittedLine[1],
//        'country': splittedLine[2],
//        'latitude': splittedLine[3],
//        'longitude': splittedLine[4],
//        'date': splittedLine[5],
//        'request': splittedLine[6].replace(/"/g, ""),
//        'status_code': splittedLine[7],
//        'content_size': splittedLine[8]
//    };
//
//    lines.push(newLineJSON);
//});
//
//app.get('/data', function (req, res) {
//  var tenLines =[];
//  for(var i = 0; i < 10; i++) {
//      tenLines.push(lines[Math.floor(Math.random()*lines.length)]);
//  }
//  res.json(tenLines);
//});

app.get('/status', function (req, res) {
  res.json({"status": "ok"})
});

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

/**
 * Migrants API
 */

var dbfile = "";
var db = {};
var filename = 'data/migr_imm5prv_1_Data.csv'

var rd = readline.createInterface({
  input: fs.createReadStream(filename, {encoding: 'utf-8'}),
  output: process.stdout,
  terminal: false
});

rd.on('line', function(line) {
  if (line.indexOf('TIME') < 0) {
    dbfile += line +'\n';
  }
});

rd.on('pause', function() {
  data = CSV.parse(dbfile);
  for (var i = 0; i < data.length; i++ ) {
    var country = data[i][1];
    var year = data[i][0];
    var origin = data[i][2];
    var age = data[i][3];
    var gender = data[i][4];
    var value = data[i][6];

    if (country.length > 0 && year.length > 0) {
      if (! (country in db)) {
        db[country] = {};
      }

      if (age == 'TOTAL' && gender == 'Total' && value !== ':') {
        db[country][year] = value;
      }
    }
  }
  console.log("Data ready.", data.length);
})

app.get('/data/summary', function (req, res) {
  res.json(db);
});

var server = app.listen(80, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('Example app listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>frappe.provide("frappe.ui");

frappe.ui.DiffView = class DiffView {
	constructor(doctype, fieldname, docname) {
		this.dialog = null;
		this.handler = null;
		this.doctype = doctype;
		this.fieldname = fieldname;
		this.docname = docname;

		this.dialog = this.make_dialog();
		this.set_empty_state();
		this.dialog.show();
	}

	make_dialog() {
		const get_query = () => ({
			query: "frappe.utils.diff.version_query",
			filters: { docname: this.docname, ref_doctype: this.doctype },
		});
		const onchange = () => this.compute_diff();
		let dialog = new frappe.ui.Dialog({
			title: __("Compare Versions"),
			fields: [
				{
					label: __("From version"),
					fieldtype: "Link",
					fieldname: "from_version",
					options: "Version",
					reqd: 1,
					get_query,
					onchange,
				},
				{
					fieldtype: "Column Break",
					fieldname: "cb",
				},
				{
					label: __("To version"),
					fieldtype: "Link",
					fieldname: "to_version",
					options: "Version",
					reqd: 1,
					get_query,
					onchange,
				},
				{
					fieldtype: "Section Break",
					fieldname: "sb",
				},
				{
					label: __("Diff"),
					fieldtype: "HTML",
					fieldname: "diff",
				},
			],
			size: "large",
		});
		return dialog;
	}

	compute_diff() {
		const from_version = this.dialog.get_value("from_version");
		const to_version = this.dialog.get_value("to_version");
		const fieldname = this.fieldname;

		if (from_version && to_version) {
			frappe
				.xcall("frappe.utils.diff.get_version_diff", {
					from_version,
					to_version,
					fieldname,
				})
				.then((data) => {
					this.dialog.set_value("diff", this.prettify_diff(data));
				});
		} else {
			this.set_empty_state();
		}
	}

	prettify_diff(diff) {
		let html = ``;

		diff.forEach((line) => {
			let line_class = "";
			if (line.startsWith("+")) {
				line_class = "insert";
			} else if (line.startsWith("-")) {
				line_class = "delete";
			}
			html += `<div class=${line_class}>${line}</div>`;
		});
		return `<div class='diffview'>${html}</div>`;
	}

	set_empty_state() {
		this.dialog.set_value("diff", __("Select two versions to view the diff."));
	}
};
<commit_msg>fix(ux): increase modal dialog size for diffview (#15666)<commit_after>frappe.provide("frappe.ui");

frappe.ui.DiffView = class DiffView {
	constructor(doctype, fieldname, docname) {
		this.dialog = null;
		this.handler = null;
		this.doctype = doctype;
		this.fieldname = fieldname;
		this.docname = docname;

		this.dialog = this.make_dialog();
		this.set_empty_state();
		this.dialog.show();
	}

	make_dialog() {
		const get_query = () => ({
			query: "frappe.utils.diff.version_query",
			filters: { docname: this.docname, ref_doctype: this.doctype },
		});
		const onchange = () => this.compute_diff();
		let dialog = new frappe.ui.Dialog({
			title: __("Compare Versions"),
			fields: [
				{
					label: __("From version"),
					fieldtype: "Link",
					fieldname: "from_version",
					options: "Version",
					reqd: 1,
					get_query,
					onchange,
				},
				{
					fieldtype: "Column Break",
					fieldname: "cb",
				},
				{
					label: __("To version"),
					fieldtype: "Link",
					fieldname: "to_version",
					options: "Version",
					reqd: 1,
					get_query,
					onchange,
				},
				{
					fieldtype: "Section Break",
					fieldname: "sb",
				},
				{
					label: __("Diff"),
					fieldtype: "HTML",
					fieldname: "diff",
				},
			],
			size: "extra-large",
		});
		return dialog;
	}

	compute_diff() {
		const from_version = this.dialog.get_value("from_version");
		const to_version = this.dialog.get_value("to_version");
		const fieldname = this.fieldname;

		if (from_version && to_version) {
			frappe
				.xcall("frappe.utils.diff.get_version_diff", {
					from_version,
					to_version,
					fieldname,
				})
				.then((data) => {
					this.dialog.set_value("diff", this.prettify_diff(data));
				});
		} else {
			this.set_empty_state();
		}
	}

	prettify_diff(diff) {
		let html = ``;

		diff.forEach((line) => {
			let line_class = "";
			if (line.startsWith("+")) {
				line_class = "insert";
			} else if (line.startsWith("-")) {
				line_class = "delete";
			}
			html += `<div class=${line_class}>${line}</div>`;
		});
		return `<div class='diffview'>${html}</div>`;
	}

	set_empty_state() {
		this.dialog.set_value("diff", __("Select two versions to view the diff."));
	}
};
<|endoftext|>


<commit_before>/**
 * I calculate a field value based on a provided mathematical string
 *
 * @homepage https://github.com/Anthropic/angular-schema-form-calculate
 *
 * NOTE: This version is not in sync with the source repo as it has
 * been modified to work with the new version of the framework in development
 *
 * @example
 * {
 *   "type":"calculate",
 *   "key":"area", // the key to COPY the RESULT to (doesn't need 'model' prefix)
 *   "watch":["length","width"], // The KEYS to WATCH for changes
 *   "calculate":"model.length * model.width"
 * }
 */
angular
  .module('schemaForm')
  .run(function($templateCache) {
    // A template to use
    $templateCache.put('calculated-fields.html','<calculate sf-field-model model="model" form="form" />');
  })
  .directive('calculate', ['$compile', '$http', 'sfBuilder', 'sfSelect', '$interpolate', 'schemaFormDecorators',
    function($compile, $http, sfBuilder, sfSelect, $interpolate, schemaFormDecoratorsProvider) {
      return {
        restrict: 'E',
        scope: true,
        link: {
          post: function(scope, element, attrs, ctrl) {
            var watchKeys = scope.form.watch,
                key, keyFixed, exec,
                i;

            scope.form.format = scope.form.format || 'number';

            for (i=0; i < watchKeys.length; i++) {
              key = watchKeys[i].split('[]');
              keyFixed = key.reduce(function(pv, cv, ci, ta){
                return '' + pv + ((cv[0]=='.')? '['+scope.$i[ci-1]+']'+cv: cv);
              });

              scope.$watch(keyFixed,
              function (val, old) {
                var newValue = $interpolate('{{' + scope.form.calculate + '}}', false, null, true)({
                  model: scope.model,
                  $i: scope.$i,
                  $index: scope.$index,
                  path: scope.path
                });

                if(scope.form.lookup) {
                  scope.model.calculated = encodeURIComponent(newValue);
                  var lookup = $interpolate(scope.form.lookup, false, null, true)(scope.model);
                  $http.get(lookup, { responseType: 'json' })
                    .success(function(response, status) {
                      if(response.data) update(response.data);
                    })
                    .error(function(data, status) {
                      scope.form.options = [];
                      scope.form.selectedOption = '';
                    });
                }
                else {
                  update(newValue);
                };

                function update(value) {
                  if(scope.form.format == 'number') value = Number(value);
                  sfSelect(scope.form.key, scope.model, value);
                };
              });
            };
          }
        }
      };
    }
  ])
  .config([ 'schemaFormDecoratorsProvider', 'sfBuilderProvider',
    function(schemaFormDecoratorsProvider, sfBuilderProvider) {
      var sfField             = sfBuilderProvider.builders.sfField;
      var ngModel             = sfBuilderProvider.builders.ngModel;
      var ngModelOptions      = sfBuilderProvider.builders.ngModelOptions;
      var defaults = [ sfField, ngModel ];

      schemaFormDecoratorsProvider.defineAddOn(
        'bootstrapDecorator',
        'calculate',
        'calculated-fields.html',
        defaults
      );
    }
  ]);
<commit_msg>Add another example to calculate add-on<commit_after>/**
 * I calculate a field value based on a provided mathematical string
 *
 * @homepage https://github.com/Anthropic/angular-schema-form-calculate
 *
 * NOTE: This version is not in sync with the source repo as it has
 * been modified to work with the new version of the framework in development
 *
 * @example
 * {
 *   "type":"calculate",
 *   "key":"area", // the key to COPY the RESULT to (doesn't need 'model' prefix)
 *   "watch":["length","width"], // The KEYS to WATCH for changes
 *   "calculate":"model.length * model.width"
 * }
 * @example
 * {
 *   "type":"calculate",
 *   "format":"number", // The format to coerce the response into, currently supports 'number' or no property defined
 *   "key":"area", // the key to COPY the RESULT to (doesn't need 'model' prefix)
 *   "watch":["length","width"], // The KEYS to WATCH for changes
 *   "calculate":"model.length * model.width",
 *   "lookup":"http://example.com/validate/{{calculated}}" // The response is copied to the key
 * }
 */
angular
  .module('schemaForm')
  .run(function($templateCache) {
    // A template to use
    $templateCache.put('calculated-fields.html','<calculate sf-field-model model="model" form="form" />');
  })
  .directive('calculate', ['$compile', '$http', 'sfBuilder', 'sfSelect', '$interpolate', 'schemaFormDecorators',
    function($compile, $http, sfBuilder, sfSelect, $interpolate, schemaFormDecoratorsProvider) {
      return {
        restrict: 'E',
        scope: true,
        link: {
          post: function(scope, element, attrs, ctrl) {
            var watchKeys = scope.form.watch,
                key, keyFixed, exec,
                i;

            scope.form.format = scope.form.format || 'number';

            for (i=0; i < watchKeys.length; i++) {
              key = watchKeys[i].split('[]');
              keyFixed = key.reduce(function(pv, cv, ci, ta){
                return '' + pv + ((cv[0]=='.')? '['+scope.$i[ci-1]+']'+cv: cv);
              });

              scope.$watch(keyFixed,
              function (val, old) {
                var newValue = $interpolate('{{' + scope.form.calculate + '}}', false, null, true)({
                  model: scope.model,
                  $i: scope.$i,
                  $index: scope.$index,
                  path: scope.path
                });

                if(scope.form.lookup) {
                  scope.model.calculated = encodeURIComponent(newValue);
                  var lookup = $interpolate(scope.form.lookup, false, null, true)(scope.model);
                  $http.get(lookup, { responseType: 'json' })
                    .success(function(response, status) {
                      if(response.data) update(response.data);
                    })
                    .error(function(data, status) {
                      scope.form.options = [];
                      scope.form.selectedOption = '';
                    });
                }
                else {
                  update(newValue);
                };

                function update(value) {
                  if(scope.form.format == 'number') value = Number(value);
                  sfSelect(scope.form.key, scope.model, value);
                };
              });
            };
          }
        }
      };
    }
  ])
  .config([ 'schemaFormDecoratorsProvider', 'sfBuilderProvider',
    function(schemaFormDecoratorsProvider, sfBuilderProvider) {
      var sfField             = sfBuilderProvider.builders.sfField;
      var ngModel             = sfBuilderProvider.builders.ngModel;
      var ngModelOptions      = sfBuilderProvider.builders.ngModelOptions;
      var defaults = [ sfField, ngModel ];

      schemaFormDecoratorsProvider.defineAddOn(
        'bootstrapDecorator',
        'calculate',
        'calculated-fields.html',
        defaults
      );
    }
  ]);
<|endoftext|>


<commit_before>var fa = require('markdown-it-fontawesome');
const markdown = require('markdown-it')().use(fa);

const mustache = require('mustache');
const fs       = require('fs');
const path     = require('path');
const walk 		 = require('walk');

const dateFormat = require('dateformat');
const hs_pages     = require('./pages');

const SHOULD_INCLUDE_HTML = true;

/**
   Blog page format:
   @title How to cut a pineapple
   @author Will
   @created 2011-10-10T14:48:00
   @modified 2011-10-10T14:48:00
	 @tags banana pineapple fruitcake
**/

function parseMDAttributes(mddata,attributes){
	var lines = mddata.split('\n');
	var outputmd = "";
  for(var l = 0;l<lines.length;l++){
		var line = lines[l].trim();
		if(line.startsWith("@")){
				var split = line.indexOf(" ");
				if(split != -1){
					var attr = line.substr(1,split-1);
					var val = line.substr(split+1);
					attributes[attr] = val;
				}
		}
		else {
				outputmd += lines[l] + '\n';
		}
	}
	return outputmd;
}

function buildPost(mddata,attributes,template,pageout){
  // var md = markdown.render(mddata);
  // const formatString = "ddd dS mmm yyyy, HH:MM ";
  // var meta = {
  //   siteindex:[],
  //   article:md,
  //   created:dateFormat(new Date(attributes["created"]),formatString),
  //   modified:dateFormat(new Date(attributes["modified"]),formatString)
  // };
  // var html = mustache.render(template,meta);
  // var name = attributes["title"].replace(/ /g,"")+".html";
  // name = name.replace(/^\.+/,""); //Build hidden anyway
  // fs.writeFile(path.join(pageout,name),html,function(err){
  //   if(err){
  //     throw err;
  //   }
  // });
	return {name:null,html:"",attribs:{}};
}

function buildBlog(indir,blogtemplate,indextemplate)
{
	blogtemplate = fs.readFileSync(blogtemplate,'utf-8');
	mustache.parse(blogtemplate);
	indextemplate = fs.readFileSync(indextemplate,'utf-8');
  var files = [];
	var blogFile = (root, fileStats, next) => {
		if(!fileStats.name.endsWith(".md")){
			next();
			return;
		}

		var attributes = {};
		var realpath = path.join(root,fileStats.name);
		var data = fs.readFileSync(realpath,'utf-8');
		data = parseMDAttributes(data,attributes);
		var date = new Date(attributes["created"]);
		var categoryString = root.replace(indir,"");
		var name = fileStats.name;
		name = name.replace(/\.(.*)/, ".html");
		var fpath = path.join(date.getFullYear().toString(),dateFormat(date,"mm"),categoryString,name);

		const formatStringC = "ddd dS mmm yyyy";
		const formatStringM = "ddd dS mmm yyyy, HH:MM ";
		attributes["dcreated"] = new Date(attributes["created"]);
		attributes["dmodified"] = new Date(attributes["modified"]);
		attributes["created"] = dateFormat(attributes["dcreated"],formatStringC);
		attributes["modified"] = dateFormat(attributes["dmodified"],formatStringM);
		attributes["article"] = markdown.render(data);
		attributes["articlemd"] = data;
		attributes["path"] = fpath;
		attributes["path"] = attributes["path"].replace(/\.(.*)/, "");
		attributes["categories"] = categoryString.replace(/\//," ");

	  files.push(
			{
				file:fpath,
				attributes:attributes,
				data:mustache.render(blogtemplate,attributes)
			});
		next();
	}
	walk.walkSync(indir,{listeners:{file:blogFile}});

	files.sort((a,b) => {
		return a.attributes.dcreated < b.attributes.dcreated;
	});

	var subset = files.slice(0,9);//Get the last 10 items;
	for (var f in subset){
		subset[f] = subset[f].attributes;
		subset[f].articlemd = subset[f].articlemd.substr(0,150) + (subset[f].articlemd.length > 150 ? "..." : "");
		subset[f].article = markdown.render(subset[f].articlemd);
	}

	files.push({"file":"index.html","data":mustache.render(indextemplate,{posts:subset})});

	//Make the blog index.
	return files;
}

module.exports = {
  buildBlog:buildBlog
}
<commit_msg>Fixed blog index having wrong title<commit_after>var fa = require('markdown-it-fontawesome');
const markdown = require('markdown-it')().use(fa);

const mustache = require('mustache');
const fs       = require('fs');
const path     = require('path');
const walk 		 = require('walk');

const dateFormat = require('dateformat');
const hs_pages     = require('./pages');

const SHOULD_INCLUDE_HTML = true;

/**
   Blog page format:
   @title How to cut a pineapple
   @author Will
   @created 2011-10-10T14:48:00
   @modified 2011-10-10T14:48:00
	 @tags banana pineapple fruitcake
**/

function parseMDAttributes(mddata,attributes){
	var lines = mddata.split('\n');
	var outputmd = "";
  for(var l = 0;l<lines.length;l++){
		var line = lines[l].trim();
		if(line.startsWith("@")){
				var split = line.indexOf(" ");
				if(split != -1){
					var attr = line.substr(1,split-1);
					var val = line.substr(split+1);
					attributes[attr] = val;
				}
		}
		else {
				outputmd += lines[l] + '\n';
		}
	}
	return outputmd;
}

function buildPost(mddata,attributes,template,pageout){
  // var md = markdown.render(mddata);
  // const formatString = "ddd dS mmm yyyy, HH:MM ";
  // var meta = {
  //   siteindex:[],
  //   article:md,
  //   created:dateFormat(new Date(attributes["created"]),formatString),
  //   modified:dateFormat(new Date(attributes["modified"]),formatString)
  // };
  // var html = mustache.render(template,meta);
  // var name = attributes["title"].replace(/ /g,"")+".html";
  // name = name.replace(/^\.+/,""); //Build hidden anyway
  // fs.writeFile(path.join(pageout,name),html,function(err){
  //   if(err){
  //     throw err;
  //   }
  // });
	return {name:null,html:"",attribs:{}};
}

function buildBlog(indir,blogtemplate,indextemplate)
{
	blogtemplate = fs.readFileSync(blogtemplate,'utf-8');
	mustache.parse(blogtemplate);
	indextemplate = fs.readFileSync(indextemplate,'utf-8');
  var files = [];
	var blogFile = (root, fileStats, next) => {
		if(!fileStats.name.endsWith(".md")){
			next();
			return;
		}

		var attributes = {};
		var realpath = path.join(root,fileStats.name);
		var data = fs.readFileSync(realpath,'utf-8');
		data = parseMDAttributes(data,attributes);
		var date = new Date(attributes["created"]);
		var categoryString = root.replace(indir,"");
		var name = fileStats.name;
		name = name.replace(/\.(.*)/, ".html");
		var fpath = path.join(date.getFullYear().toString(),dateFormat(date,"mm"),categoryString,name);

		const formatStringC = "ddd dS mmm yyyy";
		const formatStringM = "ddd dS mmm yyyy, HH:MM ";
		attributes["dcreated"] = new Date(attributes["created"]);
		attributes["dmodified"] = new Date(attributes["modified"]);
		attributes["created"] = dateFormat(attributes["dcreated"],formatStringC);
		attributes["modified"] = dateFormat(attributes["dmodified"],formatStringM);
		attributes["article"] = markdown.render(data);
		attributes["articlemd"] = data;
		attributes["path"] = fpath;
		attributes["path"] = attributes["path"].replace(/\.(.*)/, "");
		attributes["categories"] = categoryString.replace(/\//," ");

	  files.push(
			{
				file:fpath,
				attributes:attributes,
				data:mustache.render(blogtemplate,attributes)
			});
		next();
	}
	walk.walkSync(indir,{listeners:{file:blogFile}});

	files.sort((a,b) => {
		return a.attributes.dcreated < b.attributes.dcreated;
	});

	var subset = files.slice(0,9);//Get the last 10 items;
	for (var f in subset){
		subset[f] = subset[f].attributes;
		subset[f].articlemd = subset[f].articlemd.substr(0,150) + (subset[f].articlemd.length > 150 ? "..." : "");
		subset[f].article = markdown.render(subset[f].articlemd);
	}

	files.push({"file":"index.html","data":mustache.render(indextemplate,{posts:subset}),"attributes":{"title":"Blog"}});

	//Make the blog index.
	return files;
}

module.exports = {
  buildBlog:buildBlog
}
<|endoftext|>


<commit_before>//= require caboose/model/class
//= require caboose/model/model
//= require caboose/model/s3
//= require caboose/model/attribute
//= require caboose/model/model_binder
//= require caboose/model/bound_control
//= require caboose/model/bound_checkbox
//= require caboose/model/bound_checkbox_multiple
//= require caboose/model/bound_date
//= require caboose/model/bound_time
//= require caboose/model/bound_image
//= require caboose/model/bound_s3_image
//= require caboose/model/bound_file
//= require caboose/model/bound_select
//= require caboose/model/bound_text
//= require caboose/model/bound_textarea
//= require caboose/model/bound_richtext
<commit_msg>More changes<commit_after>//= require caboose/model/class
//= require caboose/model/model
//= require caboose/model/s3
//= require caboose/model/attribute
//= require caboose/model/index_table
//= require caboose/model/model_binder
//= require caboose/model/bound_control
//= require caboose/model/bound_checkbox
//= require caboose/model/bound_checkbox_multiple
//= require caboose/model/bound_date
//= require caboose/model/bound_time
//= require caboose/model/bound_image
//= require caboose/model/bound_s3_image
//= require caboose/model/bound_file
//= require caboose/model/bound_select
//= require caboose/model/bound_text
//= require caboose/model/bound_textarea
//= require caboose/model/bound_richtext
<|endoftext|>


<commit_before>'use strict';

import _ from 'lodash';
import React from 'react/addons';
import invariant from 'react/lib/invariant';
import classNames from 'classnames';
import Draggable from 'react-draggable';

import TabStyles from './TabStyles';
import CloseIcon from './CloseIcon';

import StyleOverride from '../helpers/styleOverride';
import Utils from '../helpers/utils';

let tabInlineStyles = {
};

let tabClassNames = {
};

class Tabs extends React.Component {
  constructor(props) {
    super(props);

    let defaultState = this._tabStateFromProps(this.props);
    defaultState.selectedTab = this.props.selectedTab ? this.props.selectedTab :
                                                        this.props.tabs ? this.props.tabs[0].key : '';
    defaultState.closedTabs = [];
    this.state = defaultState;

    // Dom positons
    // do not save in state
    this.startPositions = [];
  }

  _tabStateFromProps(props) {
    // setDefaultSelected
    let tabPositions = {};
    let tabs = [];
    let idx = 0;
    React.Children.forEach(props.tabs, (tab) => {

      invariant(
        tab.key,
        'There should be unique key in each Tab'
      );

      tabPositions[tab.key] = {x:0, y:0};
      tabs[idx] = tab;
      idx++;
    });

    return {
      tabs: tabs,
      tabPositions: tabPositions
    };
  }

  _isClosed(key) {
    return this.state.closedTabs.indexOf(key) > -1;
  }

  _getIndexOfTabByKey(key) {
    return _.findIndex(this.state.tabs, (tab) =>{
      return tab.key === key;
    });
  }

  _getTabByKey(key) {
    return _.where(this.state.tabs, (tab) => {
      return tab.key === key;
    });
  }

  _getNextTabKey(key) {
    let nextKey;
    let current = this._getIndexOfTabByKey(key);
    if (current + 1 < this.state.tabs.length) {
      nextKey = this.state.tabs[current + 1].key;
      if (this._isClosed(nextKey)) {
        nextKey = this._getNextTabKey(nextKey);
      }
    }
    return nextKey;
  }

  _getPrevTabKey(key) {
    let prevKey;
    let current = this._getIndexOfTabByKey(key);
    if (current > 0) {
      prevKey = this.state.tabs[current - 1].key;
      if (this._isClosed(prevKey)) {
        prevKey = this._getPrevTabKey(prevKey);
      }
    }
    return prevKey;
  }

  _getCurrentOpenTabs() {
    return this._getOpenTabs(this.state.tabs);
  }

  _getOpenTabs(tabs) {
    return _.filter(tabs, (tab) => {
      return !this._isClosed(tab.key);
    });
  }

  _moveTabPosition(key1, key2) {
    let t1 = this._getIndexOfTabByKey(key1);
    let t2 = this._getIndexOfTabByKey(key2);
    return Utils.slideArray(this.state.tabs, t1, t2);
  }

  _saveStartPositions() {
    let positions = _.map(this.state.tabs, (tab) => {
      let el = React.findDOMNode(this.refs[tab.key]);
      let pos = el ? el.getBoundingClientRect() : {};
      return {
        key: tab.key,
        pos: pos
      };
    });
    // Do not save in state
    this.startPositions = positions;
  }

  componentWillMount() {
  }

  componentDidMount() {
    this._saveStartPositions();
  }

  componentWillUnmount() {
  }

  componentWillReceiveProps(nextProps) {
    let newState = this._tabStateFromProps(nextProps);
    if (nextProps.selectedTab !== 'undefined') {
      newState.selectedTab = nextProps.selectedTab;
    }
    this.setState(newState);
  }

  componentWillUpdate() {
  }

  componentDidUpdate() {
    this._saveStartPositions();
  }

  handleMouseDown(key, e, ui) {
  }

  handleDragStart(key, e, ui) {
  }

  handleDrag(key, e, ui) {
  }

  handleDragStop(key, e, ui) {

    const deltaX = (e.pageX || e.clientX);
    let swapedTabs;
    _.each(this.startPositions, (pos) => {
      let shoudBeSwap = key !== pos.key && pos.pos.left < deltaX && deltaX < pos.pos.right;
      if (shoudBeSwap) {
        swapedTabs = this._moveTabPosition(key, pos.key);
      }
    });
    let nextTabs = swapedTabs || this.state.tabs;
    let tabPositions = this.state.tabPositions;
    tabPositions[key] = {x:0, y:0};
    this.setState({tabPositons:tabPositions, tabs: nextTabs, selectedTab: key}, () => {
      if(swapedTabs) {
        this.props.onTabPositionChanged(e, key, this._getOpenTabs(nextTabs));
      }
    });
  }

  handleTabClick(key, e) {
    let classes = e.target.className.split(' ');
    if (classes.indexOf('rdTabCloseIcon') > -1) {
      e.preventDefault();
      e.stopPropagation();
    } else {
      this.setState({selectedTab: key}, () => {
        this.props.onTabSelected(e, key, this._getCurrentOpenTabs());
      });
    }
  }

  handleCloseButtonClick(key, e) {
    let nextSelected;

    if (this.state.selectedTab === key) {
      nextSelected = this._getNextTabKey(key);
      if (!nextSelected) {
        nextSelected = this._getPrevTabKey(key);
      }
    } else {
      nextSelected = this.state.selectedTab;
    }

    let shoudBeNotifyTabChange = this.state.selectedTab !== nextSelected;

    this.setState({
      closedTabs: this.state.closedTabs.concat([key]),
      selectedTab: nextSelected
    }, ()=>{
      let currentOpenTabs = this._getCurrentOpenTabs();
      this.props.onTabClosed(e, key, currentOpenTabs);
      if (shoudBeNotifyTabChange) {
        this.props.onTabSelected(e, nextSelected, currentOpenTabs);
      }
    });
  }

  handleAddButtonClick(e) {
    this.props.onTabAddButtonClicked(e, this._getCurrentOpenTabs());
  }

  getCloseButton(tab, style, classes) {
    if (tab.props.disableClose) {
      return '';
    } else {
      let onHoverStyle = StyleOverride.merge(tabInlineStyles.tabCloseIconOnHover, tab.props.tabStyles.tabCloseIconOnHover);
      return (<CloseIcon
        style={style}
        hoverStyle={onHoverStyle}
        className={classes}
        onClick={this.handleCloseButtonClick.bind(this, tab.key)}>×</CloseIcon>);
    }
  }

  render() {

    // override inline tabs styles
    tabInlineStyles.tabBar = StyleOverride.merge(TabStyles.tabBar, this.props.tabsStyles.tabBar);
    tabInlineStyles.tabBarAfter = StyleOverride.merge(TabStyles.tabBarAfter, this.props.tabsStyles.tabBarAfter);
    tabInlineStyles.tab = StyleOverride.merge(TabStyles.tab, this.props.tabsStyles.tab);
    tabInlineStyles.tabBefore = StyleOverride.merge(TabStyles.tabBefore, this.props.tabsStyles.tabBefore);
    tabInlineStyles.tabAfter = StyleOverride.merge(TabStyles.tabAfter, this.props.tabsStyles.tabAfter);
    tabInlineStyles.tabTitle = StyleOverride.merge(TabStyles.tabTitle, this.props.tabsStyles.tabTitle);
    tabInlineStyles.tabCloseIcon = StyleOverride.merge(TabStyles.tabCloseIcon, this.props.tabsStyles.tabCloseIcon);
    tabInlineStyles.tabCloseIconOnHover = StyleOverride.merge(TabStyles.tabCloseIconOnHover, this.props.tabsStyles.tabCloseIconOnHover);

    tabInlineStyles.tabActive = StyleOverride.merge(TabStyles.tabActive, this.props.tabsStyles.tabActive);
    tabInlineStyles.tabTitleActive = StyleOverride.merge(TabStyles.tabTitleActive, this.props.tabsStyles.tabTitleActive);
    tabInlineStyles.tabBeforeActive = StyleOverride.merge(TabStyles.tabBeforeActive, this.props.tabsStyles.tabBeforeActive);
    tabInlineStyles.tabAfterActive = StyleOverride.merge(TabStyles.tabAfterActive, this.props.tabsStyles.tabAfterActive);

    // append tabs classNames
    tabClassNames.tabBar = classNames('rdTabBar', this.props.tabsClassNames.tabBar);
    tabClassNames.tabBarAfter = classNames('rdTabBarAfter', this.props.tabsClassNames.tabBarAfter);
    tabClassNames.tab = classNames('rdTab', this.props.tabsClassNames.tab);
    tabClassNames.tabBefore = classNames('rdTabBefore', this.props.tabsClassNames.tabBefore);
    tabClassNames.tabAfter = classNames('rdTabAfter', this.props.tabsClassNames.tabAfter);
    tabClassNames.tabTitle = classNames('rdTabTitle', this.props.tabsClassNames.tabTitle);
    tabClassNames.tabCloseIcon = classNames('rdTabCloseIcon', this.props.tabsClassNames.tabCloseIcon);
    tabClassNames.tabActive = classNames('rdTabActive', this.props.tabsClassNames.tabActive);

    let content;
    let tabs = _.map(this.state.tabs, (tab) => {

      if (this.state.closedTabs.indexOf(tab.key) > -1) {
        return '';
      }

      // override inline each tab styles
      let tabStyle = StyleOverride.merge(tabInlineStyles.tab, tab.props.tabStyles.tab);
      let tabBeforeStyle = StyleOverride.merge(tabInlineStyles.tabBefore, tab.props.tabStyles.tabBefore);
      let tabAfterStyle = StyleOverride.merge(tabInlineStyles.tabAfter, tab.props.tabStyles.tabAfter);
      let tabTiteleStyle = StyleOverride.merge(tabInlineStyles.tabTitle, tab.props.tabStyles.tabTitle);
      let tabCloseIconStyle = StyleOverride.merge(tabInlineStyles.tabCloseIcon, tab.props.tabStyles.tabCloseIcon);

      let tabClasses = classNames(tabClassNames.tab, tab.props.tabClassNames.tab);
      let tabBeforeClasses = classNames(tabClassNames.tabBefore, tab.props.tabClassNames.tabBefore);
      let tabAfterClasses = classNames(tabClassNames.tabAfter, tab.props.tabClassNames.tabAfter);
      let tabTitleClasses = classNames(tabClassNames.tabTitle, tab.props.tabClassNames.tabTitle);
      let tabCloseIconClasses = classNames(tabClassNames.tabCloseIcon, tab.props.tabClassNames.tabCloseIcon);

      if (this.state.selectedTab === tab.key) {
        tabStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tab, tabInlineStyles.tabActive), tab.props.tabStyles.tabActive);
        tabBeforeStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabBefore, tabInlineStyles.tabBeforeActive), tab.props.tabStyles.tabBeforeActive);
        tabAfterStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabAfter, tabInlineStyles.tabAfterActive), tab.props.tabStyles.tabAfterActive);
        tabTiteleStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabTitle, tabInlineStyles.tabTitleActive), tab.props.tabStyles.tabTitleActive);
        tabClasses = classNames(tabClassNames.tab, 'rdTabActive', this.props.tabsClassNames.tabActive, tab.props.tabClassNames.tabActive);
        content = tab;
      }

      // title will be shorten with inline style
      //  {
      //    overflow: 'hidden',
      //    whiteSpace: 'nowrap',
      //    textOverflow: 'ellipsis'
      //  }
      let tabTitle = tab.props.title;
      let tabPositon = this.state.tabPositions[tab.key];
      let closeButton = this.getCloseButton(tab, tabCloseIconStyle, tabCloseIconClasses);

      return (
        <Draggable
          key={'draggable_tabs_' + tab.key }
          axis='x'
          cancel='.rdTabCloseIcon'
          start={tabPositon}
          moveOnStartChange={true}
          zIndex={100}
          bounds='parent'
          onStart={this.handleDragStart.bind(this, tab.key)}
          onDrag={this.handleDrag.bind(this, tab.key)}
          onStop={this.handleDragStop.bind(this, tab.key)}>

            {tabTitle}
            {closeButton}

        </Draggable>
      );
    });

    return (

            {tabs}

              {this.props.tabAddButton}

        {content}

    );
  }
}

Tabs.defaultProps = {
  tabsClassNames: {
    tabBar: '',
    tabBarAfter: '',
    tab: '',
    tabBefore: '',
    tabAfter: '',
    tabTitle: '',
    tabCloseIcon: '',
    tabActive: ''
  },
  tabsStyles: {},
  tabAddButton: ({'+'}),
  onTabSelected: () => {},
  onTabClosed: () => {},
  onTabAddButtonClicked: () => {},
  onTabPositionChanged: () => {}
};

Tabs.propTypes = {
  tabs: React.PropTypes.arrayOf(React.PropTypes.element),

  selectedTab: React.PropTypes.string,
  tabsClassNames: React.PropTypes.shape({
    tabBar: React.PropTypes.string,
    tabBarAfter: React.PropTypes.string,
    tab: React.PropTypes.string,
    tabBefore: React.PropTypes.string,
    tabAfter: React.PropTypes.string,
    tabTitle: React.PropTypes.string,
    tabCloseIcon: React.PropTypes.string,
    tabActive: React.PropTypes.string
  }),
  tabsStyles: React.PropTypes.shape({
    tabBar: React.PropTypes.object,
    tabBarAfter: React.PropTypes.object,
    tab: React.PropTypes.object,
    tabBefore: React.PropTypes.object,
    tabAfter: React.PropTypes.object,
    tabTitle: React.PropTypes.object,
    tabActive: React.PropTypes.object,
    tabTitleActive: React.PropTypes.object,
    tabBeforeActive: React.PropTypes.object,
    tabAfterActive: React.PropTypes.object,
    tabCloseIcon: React.PropTypes.object,
    tabCloseIconOnHover: React.PropTypes.object
  }),
  tabAddButton: React.PropTypes.element,
  onTabSelected: React.PropTypes.func,
  onTabClosed: React.PropTypes.func,
  onTabAddButtonClicked: React.PropTypes.func,
  onTabPositionChanged: React.PropTypes.func
};

export default Tabs;
<commit_msg>Fix #8 Show closed tab when it supplied again with same key<commit_after>'use strict';

import _ from 'lodash';
import React from 'react/addons';
import invariant from 'react/lib/invariant';
import classNames from 'classnames';
import Draggable from 'react-draggable';

import TabStyles from './TabStyles';
import CloseIcon from './CloseIcon';

import StyleOverride from '../helpers/styleOverride';
import Utils from '../helpers/utils';

let tabInlineStyles = {
};

let tabClassNames = {
};

class Tabs extends React.Component {
  constructor(props) {
    super(props);

    let defaultState = this._tabStateFromProps(this.props);
    defaultState.selectedTab = this.props.selectedTab ? this.props.selectedTab :
                                                        this.props.tabs ? this.props.tabs[0].key : '';
    defaultState.closedTabs = [];
    this.state = defaultState;

    // Dom positons
    // do not save in state
    this.startPositions = [];
  }

  _tabStateFromProps(props) {
    // setDefaultSelected
    let tabPositions = {};
    let tabs = [];
    let idx = 0;
    React.Children.forEach(props.tabs, (tab) => {

      invariant(
        tab.key,
        'There should be unique key in each Tab'
      );

      tabPositions[tab.key] = {x:0, y:0};
      tabs[idx] = tab;
      idx++;
    });

    return {
      tabs: tabs,
      tabPositions: tabPositions
    };
  }

  _isClosed(key) {
    return this.state.closedTabs.indexOf(key) > -1;
  }

  _getIndexOfTabByKey(key) {
    return _.findIndex(this.state.tabs, (tab) =>{
      return tab.key === key;
    });
  }

  _getTabByKey(key) {
    return _.where(this.state.tabs, (tab) => {
      return tab.key === key;
    });
  }

  _getNextTabKey(key) {
    let nextKey;
    let current = this._getIndexOfTabByKey(key);
    if (current + 1 < this.state.tabs.length) {
      nextKey = this.state.tabs[current + 1].key;
      if (this._isClosed(nextKey)) {
        nextKey = this._getNextTabKey(nextKey);
      }
    }
    return nextKey;
  }

  _getPrevTabKey(key) {
    let prevKey;
    let current = this._getIndexOfTabByKey(key);
    if (current > 0) {
      prevKey = this.state.tabs[current - 1].key;
      if (this._isClosed(prevKey)) {
        prevKey = this._getPrevTabKey(prevKey);
      }
    }
    return prevKey;
  }

  _getCurrentOpenTabs() {
    return this._getOpenTabs(this.state.tabs);
  }

  _getOpenTabs(tabs) {
    return _.filter(tabs, (tab) => {
      return !this._isClosed(tab.key);
    });
  }

  _moveTabPosition(key1, key2) {
    let t1 = this._getIndexOfTabByKey(key1);
    let t2 = this._getIndexOfTabByKey(key2);
    return Utils.slideArray(this.state.tabs, t1, t2);
  }

  _saveStartPositions() {
    let positions = _.map(this.state.tabs, (tab) => {
      let el = React.findDOMNode(this.refs[tab.key]);
      let pos = el ? el.getBoundingClientRect() : {};
      return {
        key: tab.key,
        pos: pos
      };
    });
    // Do not save in state
    this.startPositions = positions;
  }

  componentWillMount() {
  }

  componentDidMount() {
    this._saveStartPositions();
  }

  componentWillUnmount() {
  }

  componentWillReceiveProps(nextProps) {
    let newState = this._tabStateFromProps(nextProps);
    if (nextProps.selectedTab !== 'undefined') {
      newState.selectedTab = nextProps.selectedTab;
    }
    // reset closedTabs, respect props from application
    newState.closedTabs = [];
    this.setState(newState);
  }

  componentWillUpdate() {
  }

  componentDidUpdate() {
    this._saveStartPositions();
  }

  handleMouseDown(key, e, ui) {
  }

  handleDragStart(key, e, ui) {
  }

  handleDrag(key, e, ui) {
  }

  handleDragStop(key, e, ui) {

    const deltaX = (e.pageX || e.clientX);
    let swapedTabs;
    _.each(this.startPositions, (pos) => {
      let shoudBeSwap = key !== pos.key && pos.pos.left < deltaX && deltaX < pos.pos.right;
      if (shoudBeSwap) {
        swapedTabs = this._moveTabPosition(key, pos.key);
      }
    });
    let nextTabs = swapedTabs || this.state.tabs;
    let tabPositions = this.state.tabPositions;
    tabPositions[key] = {x:0, y:0};
    this.setState({tabPositons:tabPositions, tabs: nextTabs, selectedTab: key}, () => {
      if(swapedTabs) {
        this.props.onTabPositionChanged(e, key, this._getOpenTabs(nextTabs));
      }
    });
  }

  handleTabClick(key, e) {
    let classes = e.target.className.split(' ');
    if (classes.indexOf('rdTabCloseIcon') > -1) {
      e.preventDefault();
      e.stopPropagation();
    } else {
      this.setState({selectedTab: key}, () => {
        this.props.onTabSelected(e, key, this._getCurrentOpenTabs());
      });
    }
  }

  handleCloseButtonClick(key, e) {
    let nextSelected;

    if (this.state.selectedTab === key) {
      nextSelected = this._getNextTabKey(key);
      if (!nextSelected) {
        nextSelected = this._getPrevTabKey(key);
      }
    } else {
      nextSelected = this.state.selectedTab;
    }

    let shoudBeNotifyTabChange = this.state.selectedTab !== nextSelected;

    this.setState({
      closedTabs: this.state.closedTabs.concat([key]),
      selectedTab: nextSelected
    }, ()=>{
      let currentOpenTabs = this._getCurrentOpenTabs();
      this.props.onTabClosed(e, key, currentOpenTabs);
      if (shoudBeNotifyTabChange) {
        this.props.onTabSelected(e, nextSelected, currentOpenTabs);
      }
    });
  }

  handleAddButtonClick(e) {
    this.props.onTabAddButtonClicked(e, this._getCurrentOpenTabs());
  }

  getCloseButton(tab, style, classes) {
    if (tab.props.disableClose) {
      return '';
    } else {
      let onHoverStyle = StyleOverride.merge(tabInlineStyles.tabCloseIconOnHover, tab.props.tabStyles.tabCloseIconOnHover);
      return (<CloseIcon
        style={style}
        hoverStyle={onHoverStyle}
        className={classes}
        onClick={this.handleCloseButtonClick.bind(this, tab.key)}>×</CloseIcon>);
    }
  }

  render() {

    // override inline tabs styles
    tabInlineStyles.tabBar = StyleOverride.merge(TabStyles.tabBar, this.props.tabsStyles.tabBar);
    tabInlineStyles.tabBarAfter = StyleOverride.merge(TabStyles.tabBarAfter, this.props.tabsStyles.tabBarAfter);
    tabInlineStyles.tab = StyleOverride.merge(TabStyles.tab, this.props.tabsStyles.tab);
    tabInlineStyles.tabBefore = StyleOverride.merge(TabStyles.tabBefore, this.props.tabsStyles.tabBefore);
    tabInlineStyles.tabAfter = StyleOverride.merge(TabStyles.tabAfter, this.props.tabsStyles.tabAfter);
    tabInlineStyles.tabTitle = StyleOverride.merge(TabStyles.tabTitle, this.props.tabsStyles.tabTitle);
    tabInlineStyles.tabCloseIcon = StyleOverride.merge(TabStyles.tabCloseIcon, this.props.tabsStyles.tabCloseIcon);
    tabInlineStyles.tabCloseIconOnHover = StyleOverride.merge(TabStyles.tabCloseIconOnHover, this.props.tabsStyles.tabCloseIconOnHover);

    tabInlineStyles.tabActive = StyleOverride.merge(TabStyles.tabActive, this.props.tabsStyles.tabActive);
    tabInlineStyles.tabTitleActive = StyleOverride.merge(TabStyles.tabTitleActive, this.props.tabsStyles.tabTitleActive);
    tabInlineStyles.tabBeforeActive = StyleOverride.merge(TabStyles.tabBeforeActive, this.props.tabsStyles.tabBeforeActive);
    tabInlineStyles.tabAfterActive = StyleOverride.merge(TabStyles.tabAfterActive, this.props.tabsStyles.tabAfterActive);

    // append tabs classNames
    tabClassNames.tabBar = classNames('rdTabBar', this.props.tabsClassNames.tabBar);
    tabClassNames.tabBarAfter = classNames('rdTabBarAfter', this.props.tabsClassNames.tabBarAfter);
    tabClassNames.tab = classNames('rdTab', this.props.tabsClassNames.tab);
    tabClassNames.tabBefore = classNames('rdTabBefore', this.props.tabsClassNames.tabBefore);
    tabClassNames.tabAfter = classNames('rdTabAfter', this.props.tabsClassNames.tabAfter);
    tabClassNames.tabTitle = classNames('rdTabTitle', this.props.tabsClassNames.tabTitle);
    tabClassNames.tabCloseIcon = classNames('rdTabCloseIcon', this.props.tabsClassNames.tabCloseIcon);
    tabClassNames.tabActive = classNames('rdTabActive', this.props.tabsClassNames.tabActive);

    let content;
    let tabs = _.map(this.state.tabs, (tab) => {

      if (this.state.closedTabs.indexOf(tab.key) > -1) {
        return '';
      }

      // override inline each tab styles
      let tabStyle = StyleOverride.merge(tabInlineStyles.tab, tab.props.tabStyles.tab);
      let tabBeforeStyle = StyleOverride.merge(tabInlineStyles.tabBefore, tab.props.tabStyles.tabBefore);
      let tabAfterStyle = StyleOverride.merge(tabInlineStyles.tabAfter, tab.props.tabStyles.tabAfter);
      let tabTiteleStyle = StyleOverride.merge(tabInlineStyles.tabTitle, tab.props.tabStyles.tabTitle);
      let tabCloseIconStyle = StyleOverride.merge(tabInlineStyles.tabCloseIcon, tab.props.tabStyles.tabCloseIcon);

      let tabClasses = classNames(tabClassNames.tab, tab.props.tabClassNames.tab);
      let tabBeforeClasses = classNames(tabClassNames.tabBefore, tab.props.tabClassNames.tabBefore);
      let tabAfterClasses = classNames(tabClassNames.tabAfter, tab.props.tabClassNames.tabAfter);
      let tabTitleClasses = classNames(tabClassNames.tabTitle, tab.props.tabClassNames.tabTitle);
      let tabCloseIconClasses = classNames(tabClassNames.tabCloseIcon, tab.props.tabClassNames.tabCloseIcon);

      if (this.state.selectedTab === tab.key) {
        tabStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tab, tabInlineStyles.tabActive), tab.props.tabStyles.tabActive);
        tabBeforeStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabBefore, tabInlineStyles.tabBeforeActive), tab.props.tabStyles.tabBeforeActive);
        tabAfterStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabAfter, tabInlineStyles.tabAfterActive), tab.props.tabStyles.tabAfterActive);
        tabTiteleStyle = StyleOverride.merge(StyleOverride.merge(tabInlineStyles.tabTitle, tabInlineStyles.tabTitleActive), tab.props.tabStyles.tabTitleActive);
        tabClasses = classNames(tabClassNames.tab, 'rdTabActive', this.props.tabsClassNames.tabActive, tab.props.tabClassNames.tabActive);
        content = tab;
      }

      // title will be shorten with inline style
      //  {
      //    overflow: 'hidden',
      //    whiteSpace: 'nowrap',
      //    textOverflow: 'ellipsis'
      //  }
      let tabTitle = tab.props.title;
      let tabPositon = this.state.tabPositions[tab.key];
      let closeButton = this.getCloseButton(tab, tabCloseIconStyle, tabCloseIconClasses);

      return (
        <Draggable
          key={'draggable_tabs_' + tab.key }
          axis='x'
          cancel='.rdTabCloseIcon'
          start={tabPositon}
          moveOnStartChange={true}
          zIndex={100}
          bounds='parent'
          onStart={this.handleDragStart.bind(this, tab.key)}
          onDrag={this.handleDrag.bind(this, tab.key)}
          onStop={this.handleDragStop.bind(this, tab.key)}>

            {tabTitle}
            {closeButton}

        </Draggable>
      );
    });

    return (

            {tabs}

              {this.props.tabAddButton}

        {content}

    );
  }
}

Tabs.defaultProps = {
  tabsClassNames: {
    tabBar: '',
    tabBarAfter: '',
    tab: '',
    tabBefore: '',
    tabAfter: '',
    tabTitle: '',
    tabCloseIcon: '',
    tabActive: ''
  },
  tabsStyles: {},
  tabAddButton: ({'+'}),
  onTabSelected: () => {},
  onTabClosed: () => {},
  onTabAddButtonClicked: () => {},
  onTabPositionChanged: () => {}
};

Tabs.propTypes = {
  tabs: React.PropTypes.arrayOf(React.PropTypes.element),

  selectedTab: React.PropTypes.string,
  tabsClassNames: React.PropTypes.shape({
    tabBar: React.PropTypes.string,
    tabBarAfter: React.PropTypes.string,
    tab: React.PropTypes.string,
    tabBefore: React.PropTypes.string,
    tabAfter: React.PropTypes.string,
    tabTitle: React.PropTypes.string,
    tabCloseIcon: React.PropTypes.string,
    tabActive: React.PropTypes.string
  }),
  tabsStyles: React.PropTypes.shape({
    tabBar: React.PropTypes.object,
    tabBarAfter: React.PropTypes.object,
    tab: React.PropTypes.object,
    tabBefore: React.PropTypes.object,
    tabAfter: React.PropTypes.object,
    tabTitle: React.PropTypes.object,
    tabActive: React.PropTypes.object,
    tabTitleActive: React.PropTypes.object,
    tabBeforeActive: React.PropTypes.object,
    tabAfterActive: React.PropTypes.object,
    tabCloseIcon: React.PropTypes.object,
    tabCloseIconOnHover: React.PropTypes.object
  }),
  tabAddButton: React.PropTypes.element,
  onTabSelected: React.PropTypes.func,
  onTabClosed: React.PropTypes.func,
  onTabAddButtonClicked: React.PropTypes.func,
  onTabPositionChanged: React.PropTypes.func
};

export default Tabs;
<|endoftext|>


<commit_before>var Module = require('module');
var path = require('path');
var fs = require('fs');

exports.addCoverage = function addCoverage(code, filename) {
    if (!~filename.indexOf(addCoverage.subdir)) {
        return code;
    }
    var lines = code.split('\n');

    if (lines.length > 0) {
        lines[0] = 'if (!__cov["' + filename + '"]) {__cov["' + filename + '"] = { 0: 1}; }' + lines[0];
    }

    for (var i = 0; i < lines.length; i++) {
        if (lines[i].match(/^\s\*\s/)) continue;
        var name = '__cov["' + filename + '"][' + i + ']';
        var covLine = ' ' + name + ' = (' + name + ' || 0) + 1;';
        lines[i] = lines[i]
        .replace(/;$/, ';' + covLine)
        .replace(/^\s*(return|throw|break|continue)/, covLine + ' $1');
    }

    return lines.join('\n');
};

exports.init = function init(subdir) {
    if (process.env.NOCOV || global.__cov) return;
    if (!subdir) {
        subdir = process.cwd();
    } else if (!subdir.match(/^\//)) {
        subdir = path.join(process.cwd(), subdir);
    }
    global.__cov = {};
    exports.addCoverage.subdir = subdir;
    var compile = Module.prototype._compile;
    Module.prototype._compile = function (code, filename) {
        if (~filename.indexOf(subdir)) {
            code = exports.addCoverage(code, filename);
        }
        return compile.call(this, code, filename);
    };
};

exports.report = function () {
    if (process.env.NOCOV) return;
    coverageReport();
};

function coverageReport() {
    var cwd = process.cwd(),
    total_lines = 0,
    total_covered = 0,
    files = [];

    for (file in __cov) {
        if (file.search(cwd) === -1 || file.search(cwd + '/node_modules') !== -1) continue;
        var shortFileName = file.replace(cwd + '/', '');
        var id = shortFileName.replace(/[^a-z]+/gi, '-').replace(/^-|-$/, '');
        var code = syntax(fs.readFileSync(file).toString()).split('\n');
        var cnt = code.filter(function (line) {
            return line.match(/;$/) && !line.match(/^\s\*\s/);
        }).length;
        var covered = Object.keys(__cov[file]).length;
        if (covered > cnt) covered = cnt;
        var coveredPercentage = cnt === 0 ? 100 : Math.round((covered / cnt) * 100);
        total_covered += covered;
        total_lines += cnt;
        var html = '
';
        html += '
';
        html += '' + shortFileName +
            '';
        html += '

';
        var progressClass = 'progress-danger';
        if (coveredPercentage > 30) progressClass = 'progress-warning';
        if (coveredPercentage >= 80) progressClass = 'progress-success';
        html += '

' + coveredPercentage +
            '% [' + cnt + '/' +
            code.length + ']

';
        html += '
';

        html += '

';
        code.forEach(function (line, i) {
            html += '
' + line + '';
            if (__cov[file][i] && i) {
                html += '' + __cov[file][i] + '';
            }
            html += '
';
        });
        html += '

';

        if (cnt > 1) {
            files.push({
                lines: cnt,
                covered: covered,
                id: id,
                name: shortFileName,
                html: html
            });
        }
    }

    var html = files.sort(function (x, y) {
        return y.lines - x.lines;
    }).map(function (f) { return f.html }).join('\n');

    fs.writeFileSync(cwd + '/coverage.html', fs.readFileSync(path.join(__dirname, 'coverage.html')).toString().replace('CODE', html.replace(/\$'/g, '$\'')));
    console.log('====================');
    console.log('TOTAL COVERAGE:', Math.round((total_covered / (total_lines)) * 100) + '%');
}

function syntax(code) {
    var comments    = [];
    var strings     = [];
    var res         = [];
    var all         = { 'C': comments, 'S': strings, 'R': res };
    var safe        = { '<': '<', '>': '>', '&': '&' };

    return code
        .replace(/[<>&]/g, function (m)
            { return safe[m]; })
        .replace(/\/\*[\s\S]*?\*\//g, function(m)
            { var l=comments.length; comments.push(m); return '~~~C'+l+'~~~';   })
        .replace(/([^\\])((?:'(?:\\'|[^'\n])*')|(?:"(?:\\"|[^"\n])*"))/g, function(m, f, s)
            { var l=strings.length; strings.push(s); return f+'~~~S'+l+'~~~'; })
        // .replace(/\/(\\\/|[^\/\n])*\/[gim]{0,3}/g, function(m)
        //    { var l=res.length; res.push(m); return '~~~R'+l+'~~~';   })
        .replace(/(var|function|typeof|new|return|if|for|in|while|break|do|continue|switch|case)([^a-z0-9\$_])/gi,
            '$1$2')
        .replace(/(\{|\}|\]|\[|\|)/gi,
            '$1')
        .replace(/([a-z\_\$][a-z0-9_]*)[\s]*\(/gi,
            '$1(')
        .replace(/~~~([CSR])(\d+)~~~/g, replaceCSR)

    function replaceCSR(m, t, i) {
        var openTag = '';
        var closeTag = '';
        return openTag +
            all[t][i].replace(/\n/g, closeTag + '\n' + openTag) +
            closeTag;
    }
}

<commit_msg>Fixes error in windows<commit_after>var Module = require('module');
var path = require('path');
var fs = require('fs');

exports.addCoverage = function addCoverage(code, filename) {
    filename = filename.replace(/\\/g, '\\\\');
    if (!~filename.indexOf(addCoverage.subdir)) {
        return code;
    }
    var lines = code.split('\n');

    if (lines.length > 0) {
        lines[0] = 'if (!__cov["' + filename + '"]) {__cov["' + filename + '"] = { 0: 1}; }' + lines[0];
    }

    for (var i = 0; i < lines.length; i++) {
        if (lines[i].match(/^\s\*\s/)) continue;
        var name = '__cov["' + filename + '"][' + i + ']';
        var covLine = ' ' + name + ' = (' + name + ' || 0) + 1;';
        lines[i] = lines[i]
        .replace(/;$/, ';' + covLine)
        .replace(/^\s*(return|throw|break|continue)/, covLine + ' $1');
    }

    return lines.join('\n');
};

exports.init = function init(subdir) {
    if (process.env.NOCOV || global.__cov) return;
    if (!subdir) {
        subdir = process.cwd();
    } else if (!subdir.match(/^\//)) {
        subdir = path.join(process.cwd(), subdir);
    }
    global.__cov = {};
    exports.addCoverage.subdir = subdir;
    var compile = Module.prototype._compile;
    Module.prototype._compile = function (code, filename) {
        if (~filename.indexOf(subdir)) {
            code = exports.addCoverage(code, filename);
        }
        return compile.call(this, code, filename);
    };
};

exports.report = function () {
    if (process.env.NOCOV) return;
    coverageReport();
};

function coverageReport() {
    var cwd = process.cwd(),
    total_lines = 0,
    total_covered = 0,
    files = [];

    for (file in __cov) {
        if (file.search(cwd) === -1 || file.search(cwd + '/node_modules') !== -1) continue;
        var shortFileName = file.replace(cwd + '/', '');
        var id = shortFileName.replace(/[^a-z]+/gi, '-').replace(/^-|-$/, '');
        var code = syntax(fs.readFileSync(file).toString()).split('\n');
        var cnt = code.filter(function (line) {
            return line.match(/;$/) && !line.match(/^\s\*\s/);
        }).length;
        var covered = Object.keys(__cov[file]).length;
        if (covered > cnt) covered = cnt;
        var coveredPercentage = cnt === 0 ? 100 : Math.round((covered / cnt) * 100);
        total_covered += covered;
        total_lines += cnt;
        var html = '
';
        html += '
';
        html += '' + shortFileName +
            '';
        html += '

';
        var progressClass = 'progress-danger';
        if (coveredPercentage > 30) progressClass = 'progress-warning';
        if (coveredPercentage >= 80) progressClass = 'progress-success';
        html += '

' + coveredPercentage +
            '% [' + cnt + '/' +
            code.length + ']

';
        html += '
';

        html += '

';
        code.forEach(function (line, i) {
            html += '
' + line + '';
            if (__cov[file][i] && i) {
                html += '' + __cov[file][i] + '';
            }
            html += '
';
        });
        html += '

';

        if (cnt > 1) {
            files.push({
                lines: cnt,
                covered: covered,
                id: id,
                name: shortFileName,
                html: html
            });
        }
    }

    var html = files.sort(function (x, y) {
        return y.lines - x.lines;
    }).map(function (f) { return f.html }).join('\n');

    fs.writeFileSync(cwd + '/coverage.html', fs.readFileSync(path.join(__dirname, 'coverage.html')).toString().replace('CODE', html.replace(/\$'/g, '$\'')));
    console.log('====================');
    console.log('TOTAL COVERAGE:', Math.round((total_covered / (total_lines)) * 100) + '%');
}

function syntax(code) {
    var comments    = [];
    var strings     = [];
    var res         = [];
    var all         = { 'C': comments, 'S': strings, 'R': res };
    var safe        = { '<': '<', '>': '>', '&': '&' };

    return code
        .replace(/[<>&]/g, function (m)
            { return safe[m]; })
        .replace(/\/\*[\s\S]*?\*\//g, function(m)
            { var l=comments.length; comments.push(m); return '~~~C'+l+'~~~';   })
        .replace(/([^\\])((?:'(?:\\'|[^'\n])*')|(?:"(?:\\"|[^"\n])*"))/g, function(m, f, s)
            { var l=strings.length; strings.push(s); return f+'~~~S'+l+'~~~'; })
        // .replace(/\/(\\\/|[^\/\n])*\/[gim]{0,3}/g, function(m)
        //    { var l=res.length; res.push(m); return '~~~R'+l+'~~~';   })
        .replace(/(var|function|typeof|new|return|if|for|in|while|break|do|continue|switch|case)([^a-z0-9\$_])/gi,
            '$1$2')
        .replace(/(\{|\}|\]|\[|\|)/gi,
            '$1')
        .replace(/([a-z\_\$][a-z0-9_]*)[\s]*\(/gi,
            '$1(')
        .replace(/~~~([CSR])(\d+)~~~/g, replaceCSR)

    function replaceCSR(m, t, i) {
        var openTag = '';
        var closeTag = '';
        return openTag +
            all[t][i].replace(/\n/g, closeTag + '\n' + openTag) +
            closeTag;
    }
}

<|endoftext|>


<commit_before>import { equal, or } from '@ember/object/computed';
import { observer, get, set, setProperties } from '@ember/object';
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import layout from './template';

const NONE = 'none';
const TCP = 'tcp';
const HTTP = 'http';
const HTTPS = 'https';
const COMMAND = 'command';

export default Component.extend({
  scope:    service(),
  intl:     service(),
  settings: service(),

  layout,
  // Inputs
  healthCheck:      null,
  errors:           null,
  dnsNote:          false,
  successMustBeOne: false,

  editing: true,

  checkType: null,
  command:   null,
  path:      null,
  host:      null,
  headers:   null,

  isNone:    equal('checkType', NONE),
  isTcp:     equal('checkType', TCP),
  isHttp:    equal('checkType', HTTP),
  isHttps:   equal('checkType', HTTPS),
  isHttpish: or('isHttp', 'isHttps'),
  isCommand: equal('checkType', COMMAND),

  init() {
    this._super(...arguments);

    const initial = get(this, 'initialCheck');
    let check;
    let type = NONE;

    if ( initial ) {
      check = Object.assign({}, initial);
      if ( get(check, 'tcp') ) {
        type = TCP;
      } else if ( get(check, 'command.length') ) {
        type = COMMAND;
        set(this, 'command', get(check, 'command'));
      } else if ( get(check, 'scheme') === 'HTTP' ) {
        type = HTTP;
      } else if ( get(check, 'scheme') === 'HTTPS' ) {
        type = HTTPS;
      }

      if ( type === HTTP || type === HTTPS ) {
        const originalHeaders = get(check, 'httpHeaders') || {};
        let host = null;
        const headers = {};

        Object.keys(originalHeaders).forEach((key) => {
          if ( key.toLowerCase() === 'host' ) {
            host = originalHeaders[key];
          } else {
            headers[key] = originalHeaders[key];
          }
        });

        set(this, 'path', get(check, 'path'));
        set(this, 'host', host);
        set(this, 'headers', headers);
      }
    } else {
      check = get(this, 'store').createRecord({
        type:                'probe',
        failureThreshold:    3,
        initialDelaySeconds: 10,
        path:                '/',
        periodSeconds:       2,
        successThreshold:    2,
        timeoutSeconds:      2,
      });
    }

    if ( get(this, 'successMustBeOne') ) {
      set(check, 'successThreshold', 1);
    }

    set(this, 'healthCheck', check);
    set(this, 'checkType', type);
    this.validate();
  },

  checkChanged: observer('path', 'host', 'headers', 'checkType', 'command', function() {
    const check = get(this, 'healthCheck');

    if ( get(this, 'isNone') ) {
      this.sendAction('changed', null);

      return;
    }

    setProperties(check, { tcp: get(this, 'isTcp') });

    if ( get(this, 'isHttpish') ) {
      const host = get(this, 'host');
      const hostHeader = {};

      if ( host ) {
        hostHeader['Host'] = host;
      }

      const headers = Object.assign({}, hostHeader, get(this, 'headers'));

      setProperties(check, {
        httpHeaders: headers,
        path:        get(this, 'path') || '/',
        scheme:      get(this, 'isHttps') ? 'HTTPS' : 'HTTP'
      });
    } else {
      setProperties(check, {
        path:        null,
        httpHeaders: null,
      });
    }

    if ( get(this, 'isCommand') ) {
      set(check, 'command', get(this, 'command') );
    } else {
      set(check, 'command', null);
    }

    this.sendAction('changed', check);
  }),

  validate: observer('isNone', 'isCommand', 'healthCheck.command.[]', 'healthCheck.port', function() {
    var errors = [];

    set(this, 'errors', errors);

    if ( get(this, 'isNone') ) {
      return;
    }

    if ( get(this, 'isCommand') ) {
      if ( !get(this, 'healthCheck.command.length') ) {
        errors.push('Health Check command is required');
      }
    } else {
      if ( !get(this, 'healthCheck.port') ) {
        errors.push('Health Check port is required');
      }
    }
  }),
});
<commit_msg>Fix health check cannot update initialDelaySeconds<commit_after>import { equal, or } from '@ember/object/computed';
import { observer, get, set, setProperties } from '@ember/object';
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import layout from './template';
import { scheduleOnce } from '@ember/runloop';

const NONE = 'none';
const TCP = 'tcp';
const HTTP = 'http';
const HTTPS = 'https';
const COMMAND = 'command';

export default Component.extend({
  scope:    service(),
  intl:     service(),
  settings: service(),

  layout,
  // Inputs
  healthCheck:      null,
  errors:           null,
  dnsNote:          false,
  successMustBeOne: false,

  editing: true,

  checkType: null,
  command:   null,
  path:      null,
  host:      null,
  headers:   null,

  isNone:    equal('checkType', NONE),
  isTcp:     equal('checkType', TCP),
  isHttp:    equal('checkType', HTTP),
  isHttps:   equal('checkType', HTTPS),
  isHttpish: or('isHttp', 'isHttps'),
  isCommand: equal('checkType', COMMAND),

  init() {
    this._super(...arguments);

    const initial = get(this, 'initialCheck');
    let check;
    let type = NONE;

    if ( initial ) {
      check = Object.assign({}, initial);
      if ( get(check, 'tcp') ) {
        type = TCP;
      } else if ( get(check, 'command.length') ) {
        type = COMMAND;
        set(this, 'command', get(check, 'command'));
      } else if ( get(check, 'scheme') === 'HTTP' ) {
        type = HTTP;
      } else if ( get(check, 'scheme') === 'HTTPS' ) {
        type = HTTPS;
      }

      if ( type === HTTP || type === HTTPS ) {
        const originalHeaders = get(check, 'httpHeaders') || {};
        let host = null;
        const headers = {};

        Object.keys(originalHeaders).forEach((key) => {
          if ( key.toLowerCase() === 'host' ) {
            host = originalHeaders[key];
          } else {
            headers[key] = originalHeaders[key];
          }
        });

        set(this, 'path', get(check, 'path'));
        set(this, 'host', host);
        set(this, 'headers', headers);
      }
    } else {
      check = get(this, 'store').createRecord({
        type:                'probe',
        failureThreshold:    3,
        initialDelaySeconds: 10,
        path:                '/',
        periodSeconds:       2,
        successThreshold:    2,
        timeoutSeconds:      2,
      });
    }

    if ( get(this, 'successMustBeOne') ) {
      set(check, 'successThreshold', 1);
    }

    set(this, 'healthCheck', check);
    set(this, 'checkType', type);
    this.validate();

    scheduleOnce('afterRender', () => {
      this.checkChanged()
    });
  },

  checkChanged: observer('path', 'host', 'headers', 'checkType', 'command', function() {
    const check = get(this, 'healthCheck');

    if ( get(this, 'isNone') ) {
      this.sendAction('changed', null);

      return;
    }

    setProperties(check, { tcp: get(this, 'isTcp') });

    if ( get(this, 'isHttpish') ) {
      const host = get(this, 'host');
      const hostHeader = {};

      if ( host ) {
        hostHeader['Host'] = host;
      }

      const headers = Object.assign({}, hostHeader, get(this, 'headers'));

      setProperties(check, {
        httpHeaders: headers,
        path:        get(this, 'path') || '/',
        scheme:      get(this, 'isHttps') ? 'HTTPS' : 'HTTP'
      });
    } else {
      setProperties(check, {
        path:        null,
        httpHeaders: null,
      });
    }

    if ( get(this, 'isCommand') ) {
      set(check, 'command', get(this, 'command') );
    } else {
      set(check, 'command', null);
    }

    this.sendAction('changed', check);
  }),

  validate: observer('isNone', 'isCommand', 'healthCheck.command.[]', 'healthCheck.port', function() {
    var errors = [];

    set(this, 'errors', errors);

    if ( get(this, 'isNone') ) {
      return;
    }

    if ( get(this, 'isCommand') ) {
      if ( !get(this, 'healthCheck.command.length') ) {
        errors.push('Health Check command is required');
      }
    } else {
      if ( !get(this, 'healthCheck.port') ) {
        errors.push('Health Check port is required');
      }
    }
  }),
});
<|endoftext|>


<commit_before>const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', function () {
  createWindow();
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>Transparency<commit_after>const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow (framing, transparency) {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600, frame: framing, transparent: transparency})

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', function () {
  createWindow();
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>