<commit_before>/* @flow */

import _ from 'underscore';
import React from 'react';

// Whether `LazyImage` instances should check to load their images immediately. This will be true
// only after a period of time that allows the popup to show quickly.
let checkShoudLoadOnMount = false;

const loadedSrcs = new Set();
const pendingLazyImages = new Set();

function checkShouldLoadLazyImages() {
  for (const lazyImage of pendingLazyImages) {
    lazyImage.checkShouldLoad();
  }
}

// Begin the loading process a full second after initial execution to allow the popup to open
// before loading images. If images begin to load too soon after the popup opens, Chrome waits for
// them to fully load before showing the popup.
setTimeout(function() {
  checkShouldLoadLazyImages();
  checkShoudLoadOnMount = true;

  // Check whether to load images on scroll events but throttle the check to once every 150ms
  // because scroll events are numerous.
  window.addEventListener('scroll', _.throttle(checkShouldLoadLazyImages, 150));
}, 1000);

type Props = {
  height: number,
  src: string,
  style?: {[key: string]: any},
  width: number,
};

export default class LazyImage extends React.PureComponent {
  props: Props;
  state: {
    loaded: boolean,
  };

  _placeholder: ?HTMLElement;

  constructor(props: Props) {
    super(props);
    this.state = {
      loaded: loadedSrcs.has(this.props.src),
    };
  }

  componentDidMount() {
    if (!this.state.loaded) {
      pendingLazyImages.add(this);
      if (checkShoudLoadOnMount) this.checkShouldLoad();
    }
  }

  componentWillUnmount() {
    if (pendingLazyImages.has(this)) {
      pendingLazyImages.delete(this);
    }
    if (loadedSrcs.has(this.props.src)) {
      loadedSrcs.delete(this.props.src);
    }
  }

  checkShouldLoad() {
    if (!this._placeholder) return;

    const rect = this._placeholder.getBoundingClientRect();
    const isInViewport = (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= window.innerHeight &&
      rect.right <= window.innerWidth
    );

    if (isInViewport) {
      loadedSrcs.add(this.props.src);
      pendingLazyImages.delete(this);
      this.setState({loaded: true});
    }
  }

  render() {
    if (this.state.loaded) {
      return ;
    } else {
      const style = Object.assign({}, this.props.style, {
        background: '#ccc',
        borderRadius: `${this.props.height / 2}px`,
        display: 'inline-block',
        height: `${this.props.height}px`,
        verticalAlign: 'sub',
        width: `${this.props.width}px`,
      });
      return
 { this._placeholder = placeholder; }} style={style} />;
    }
  }
}
<commit_msg>Leave all srcs loaded<commit_after>/* @flow */

import _ from 'underscore';
import React from 'react';

// Whether `LazyImage` instances should check to load their images immediately. This will be true
// only after a period of time that allows the popup to show quickly.
let checkShoudLoadOnMount = false;

const loadedSrcs = new Set();
const pendingLazyImages = new Set();

function checkShouldLoadLazyImages() {
  for (const lazyImage of pendingLazyImages) {
    lazyImage.checkShouldLoad();
  }
}

// Begin the loading process a full second after initial execution to allow the popup to open
// before loading images. If images begin to load too soon after the popup opens, Chrome waits for
// them to fully load before showing the popup.
setTimeout(function() {
  checkShouldLoadLazyImages();
  checkShoudLoadOnMount = true;

  // Check whether to load images on scroll events but throttle the check to once every 150ms
  // because scroll events are numerous.
  window.addEventListener('scroll', _.throttle(checkShouldLoadLazyImages, 150));
}, 1000);

type Props = {
  height: number,
  src: string,
  style?: {[key: string]: any},
  width: number,
};

export default class LazyImage extends React.PureComponent {
  props: Props;
  state: {
    loaded: boolean,
  };

  _placeholder: ?HTMLElement;

  constructor(props: Props) {
    super(props);
    this.state = {
      loaded: loadedSrcs.has(this.props.src),
    };
  }

  componentDidMount() {
    if (!this.state.loaded) {
      pendingLazyImages.add(this);
      if (checkShoudLoadOnMount) this.checkShouldLoad();
    }
  }

  componentWillUnmount() {
    if (pendingLazyImages.has(this)) {
      pendingLazyImages.delete(this);
    }
  }

  checkShouldLoad() {
    if (!this._placeholder) return;

    const rect = this._placeholder.getBoundingClientRect();
    const isInViewport = (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= window.innerHeight &&
      rect.right <= window.innerWidth
    );

    if (isInViewport) {
      loadedSrcs.add(this.props.src);
      pendingLazyImages.delete(this);
      this.setState({loaded: true});
    }
  }

  render() {
    if (this.state.loaded) {
      return ;
    } else {
      const style = Object.assign({}, this.props.style, {
        background: '#ccc',
        borderRadius: `${this.props.height / 2}px`,
        display: 'inline-block',
        height: `${this.props.height}px`,
        verticalAlign: 'sub',
        width: `${this.props.width}px`,
      });
      return
 { this._placeholder = placeholder; }} style={style} />;
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Creates a gulp task that fetches the titles and files
 * of pull requests using the github API, from `branch` up to the last git tag.
 * Only includes pull requests that have code changes and not only markdown,
 * json, and yaml changes.
 */

var BBPromise = require('bluebird');
var argv = require('minimist')(process.argv.slice(2));
var assert = require('assert');
var child_process = require('child_process');
var config = require('../config');
var extend = require('util')._extend;
var git = require('gulp-git');
var gulp = require('gulp-help')(require('gulp'));
var request = BBPromise.promisify(require('request'));
var util = require('gulp-util');

var GITHUB_ACCESS_TOKEN = process.env.GITHUB_ACCESS_TOKEN;
var exec = BBPromise.promisify(child_process.exec);
var gitExec = BBPromise.promisify(git.exec);

var branch = argv.branch || 'canary';
var isDryrun = argv.dryrun;

function changelog() {
  if (!GITHUB_ACCESS_TOKEN) {
    util.log(util.colors.red('Warning! You have not set the ' +
        'GITHUB_ACCESS_TOKEN env var. Aborting "changelog" task.'));
    util.log(util.colors.green('See https://help.github.com/articles/' +
        'creating-an-access-token-for-command-line-use/ ' +
        'for instructions on how to create a github access token. We only ' +
        'need `public_repo` scope.'));
    return;
  }

  return getGitMetadata();
}

function getGitMetadata() {
  if (!argv.version) {
    throw new Error('no version value passed in. See --version flag option.');
  }

  var gitMetadata = {};
  return getLastGitTag()
      .then(onGitTagSuccess.bind(null, gitMetadata))
      .then(getGitLog)
      .then(onGitLogSuccess.bind(null, gitMetadata))
      .then(fetchGithubMetadata)
      .then(buildChangelog.bind(null, gitMetadata))
      .then(function(gitMetadata) {
        util.log(util.colors.blue('\n' + gitMetadata.changelog));
        if (isDryrun) {
          return;
        }
        return getCurrentSha().then(
          submitReleaseNotes.bind(null, argv.version, gitMetadata.changelog)
        );
      })
      .catch(errHandler);
}

function submitReleaseNotes(version, changelog, sha) {
  var name = String(version);
  var options = {
    url: 'https://api.github.com/repos/ampproject/amphtml/releases',
    method: 'POST',
    headers: {
      'User-Agent': 'amp-changelog-gulp-task',
      'Accept': 'application/vnd.github.v3+json'
    },
    json: true,
    body: {
      'tag_name': name,
      'target_commitish': sha,
      'name': name,
      'body': changelog,
      'draft': true,
      'prerelease': true
    }
  };

  if (GITHUB_ACCESS_TOKEN) {
    options.qs = {
      access_token: GITHUB_ACCESS_TOKEN
    }
  }

  return request(options).then(function() {
    util.log(util.colors.green('Release Notes submitted'));
  });
}

function getCurrentSha() {
  return gitExec({ args: 'rev-parse HEAD' }).then(function(sha) {
    return sha.trim();
  });
}

function buildChangelog(gitMetadata, githubMetadata) {
  var changelog = `## Version: ${argv.version}\n\n`;
  // append all titles
  changelog += githubMetadata
      .filter(function(data) {
        return !data.filenames.every(function(filename) {
          return config.changelogIgnoreFileTypes.test(filename);
        });
      })
      .map(function(data) {
        return '  - ' + data.title.trim();
      }).join('\n');
  changelog += '\n\n## Breakdown by component\n\n';
  var sections = buildSections(githubMetadata);

  Object.keys(sections).sort().forEach(function(section) {
    changelog += `### ${section}\n\n`;
    var uniqueItems = sections[section].filter(function(title, idx) {
      return sections[section].indexOf(title) == idx;
    });
    changelog += uniqueItems.join('');
    changelog += '\n';
  });

  gitMetadata.changelog = changelog;
  return gitMetadata;
}

/**
 * @param {!Array<PullRequestMetedata>} githubMetadata
 * @return {!Object}
 */
function buildSections(githubMetadata) {
  var sections = {};
  githubMetadata.forEach(function(pr) {
    var hasNonDocChange = !pr.filenames.every(function(filename) {
      return config.changelogIgnoreFileTypes.test(filename);
    });
    var listItem = `  - ${pr.title.trim()}\n`;

    if (hasNonDocChange) {
      changelog += listItem;
    }

    pr.filenames.forEach(function(filename) {
      var section;
      var body = '';
      var path = filename.split('/');
      var isExtensionChange = path[0] == 'extensions';
      var isBuiltinChange = path[0] == 'builtins';
      var isAdsChange = path[0] == 'ads';
      // TODO: figure out how to break down validator changes since
      // it is usually a big PR with a number of commits, and the commit
      // message is what is useful for a changelog.
      var isValidatorChange = path[0] == 'validator';

      if (isExtensionChange) {
        section = path[1];
      } else if (isBuiltinChange && isJs(path[1])) {
        // builtins files dont have a nested per component folder.
        section = path[1].replace(/\.js$/, '');
      } else if (isAdsChange && isJs(path[1])) {
        section = 'ads';
      } else if (isValidatorChange) {
        section = 'validator';
      }

      if (section) {
        if (!sections[section]) {
          sections[section] = [];
        }
        // if its the validator section, read the body of the PR
        // and format it correctly under the bullet list.
        if (section == 'validator') {
          body = `\n    ${pr.body.split('\n').join('\n    ')}`;
        }
        sections[section].push(listItem + body);
      }
    });
  });
  return sections;
}

/**
 * Get the latest git tag from either a normal release or from a canary release.
 * @return {!Promise<string>}
 */
function getLastGitTag() {
  var options = {
    args: `describe --abbrev=0 --first-parent --tags ${branch}`
  };
  return gitExec(options).then(function(tag) {
    return tag.trim();
  });
}

/**
 * @param {string} tag
 * @return {!Promise<string>}
 */
function getGitLog(tag) {
  var options = {
    args: 'log ' + branch + '...' + tag +
        ' --pretty=format:%s --merges --first-parent'
  };
  return gitExec(options).then(function(log) {
    if (!log) {
      throw new Error('No log found "git log ' + branch +
          '...' + tag + '".\nIs it possible that there is no delta?\n' +
          'Make sure to fetch and rebase (or reset --hard) the latest ' +
          'from remote upstream.');
    }
    return log;
  });
}

function fetchGithubMetadata(ids) {
  var options = {
    url: 'https://api.github.com/repos/ampproject/amphtml/pulls/',
    headers: {
      'User-Agent': 'amp-changelog-gulp-task'
    }
  };

  if (GITHUB_ACCESS_TOKEN) {
    options.qs = {
      access_token: GITHUB_ACCESS_TOKEN
    }
  }

  // NOTE: (erwinm) not sure if theres a better way to do this, we're
  // doing n + 1 fetches here since we can't batch things up.
  var requests = ids.map(function(id) {
    var prOption = extend({}, options);
    prOption.url += id;

    return getPullRequestMetadata(prOption).then(function(title) {
      var filesOption = extend({}, prOption);
      filesOption.url += '/files';
      return getPullRequestFiles(title, filesOption);
    });
  });

  return BBPromise/*OK*/.all(requests);
}

function getPullRequestMetadata(prOption) {
  return request(prOption).then(function(res) {
    var body = JSON.parse(res.body);
    assert(typeof body.url == 'string', 'should have url string. ' + res.body);
    var url = body.url.split('/');
    var pr = url[url.length - 1];
    return {
      title: body.title + ' (#' + pr + ')',
      body: body.body
    };
  });
}

function getPullRequestFiles(prMetadata, filesOption) {
  return request(filesOption).then(function(res) {
    var body = JSON.parse(res.body);

    assert(Array.isArray(body) && body.length > 0,
        'Pull request response must not be empty. ' + res.body);
    var filenames = body.map(function(file) {
      return file.filename;
    });

    return {
      body: prMetadata.body,
      title: prMetadata.title,
      filenames: filenames
    };
  });
}

function onGitTagSuccess(gitMetadata, tag) {
  if (!tag) {
    throw new Error('Could not find latest ' + branch + ' tag.');
  }

  gitMetadata.tag = tag;
  util.log(util.colors.green('Current latest tag: ' + tag));
  return tag;
}

function onGitLogSuccess(gitMetadata, logs) {
  var commits = logs.split('\n');
  assert(typeof logs == 'string', 'git log should be a string.\n' + logs);
  return commits
    .filter(function(commit) {
      // Filter non Pull request merges.
      return commit.indexOf('Merge pull') == 0;
    })
    .map(function(commit) {
      // We only need the PR id
      var id = commit.split(' ')[3].slice(1);
      var value = parseInt(id, 10);
      assert(value > 0, 'Should be an integer greater than 0. ' + value);
      return id;
    });
}

function errHandler(err) {
  var msg = err;
  if (err.message) {
    msg = err.message;
  }
  util.log(util.colors.red(msg));
}

/**
 * Checks if string ends with ".js"
 * @param {string} str
 * @return {boolean}
 */
function isJs(str) {
  return str./*OK*/endsWith('.js');
}

gulp.task('changelog', 'Create github release draft', changelog, {
  options: {
    dryrun: '  Generate changelog but dont push it out',
    type: '  Pass in "canary" to generate a canary changelog',
    version: '  The git tag and github release label',
  }
});
<commit_msg>tools(changelog): handle non merge commits<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Creates a gulp task that fetches the titles and files
 * of pull requests using the github API, from `branch` up to the last git tag.
 * Only includes pull requests that have code changes and not only markdown,
 * json, and yaml changes.
 */

var BBPromise = require('bluebird');
var argv = require('minimist')(process.argv.slice(2));
var assert = require('assert');
var child_process = require('child_process');
var config = require('../config');
var extend = require('util')._extend;
var git = require('gulp-git');
var gulp = require('gulp-help')(require('gulp'));
var request = BBPromise.promisify(require('request'));
var util = require('gulp-util');

var GITHUB_ACCESS_TOKEN = process.env.GITHUB_ACCESS_TOKEN;
var exec = BBPromise.promisify(child_process.exec);
var gitExec = BBPromise.promisify(git.exec);

var branch = argv.branch || 'canary';
var isDryrun = argv.dryrun;

const pullOptions = {
  url: 'https://api.github.com/repos/ampproject/amphtml/pulls',
  headers: {
    'User-Agent': 'amp-changelog-gulp-task',
  },
};

if (GITHUB_ACCESS_TOKEN) {
  pullOptions.qs = {
    access_token: GITHUB_ACCESS_TOKEN
  }
}

/**
 * @typedef {{
 *  logs: !Array<!LogMetadataDef>,
 *  tag: (string|undefined),
 *  changelog: (string|undefined)
 * }}
 */
var GitMetadataDef;

/**
 * @typedef {{
 *   title: string,
 *   sha: string,
 *   pr: (PrMetadata|undefined)
 * }}
 */
var LogMetadataDef;

/**
 * @typedef {{
 *   id: number,
 *   title: string,
 *   body: string,
 *   merge_commit_sha: string,
 *   url: string,
 *   filenames: !Array<string>
 * }}
 */
var PrMetadataDef;

function changelog() {
  if (!GITHUB_ACCESS_TOKEN) {
    util.log(util.colors.red('Warning! You have not set the ' +
        'GITHUB_ACCESS_TOKEN env var. Aborting "changelog" task.'));
    util.log(util.colors.green('See https://help.github.com/articles/' +
        'creating-an-access-token-for-command-line-use/ ' +
        'for instructions on how to create a github access token. We only ' +
        'need `public_repo` scope.'));
    return;
  }

  return getGitMetadata();
}

/**
 * @return {!Promise}
 */
function getGitMetadata() {
  if (!argv.version) {
    throw new Error('no version value passed in. See --version flag option.');
  }

  var gitMetadata = { logs: [], tag: undefined };
  return getLastGitTag(gitMetadata)
      .then(getGitLog)
      .then(getGithubPullRequestsMetadata)
      .then(getGithubFilesMetadata)
      .then(buildChangelog)
      .then(function(gitMetadata) {
        util.log(util.colors.blue('\n' + gitMetadata.changelog));
        if (isDryrun) {
          return;
        }
        return getCurrentSha().then(
          submitReleaseNotes.bind(null, argv.version, gitMetadata.changelog)
        );
      })
      .catch(errHandler);
}

/**
 * @param {string} version
 * @param {string} changelog
 * @param {string} sha
 * @return {!Promise}
 */
function submitReleaseNotes(version, changelog, sha) {
  var name = String(version);
  var options = {
    url: 'https://api.github.com/repos/ampproject/amphtml/releases',
    method: 'POST',
    headers: {
      'User-Agent': 'amp-changelog-gulp-task',
      'Accept': 'application/vnd.github.v3+json'
    },
    json: true,
    body: {
      'tag_name': name,
      'target_commitish': sha,
      'name': name,
      'body': changelog,
      'draft': true,
      'prerelease': true
    }
  };

  if (GITHUB_ACCESS_TOKEN) {
    options.qs = {
      access_token: GITHUB_ACCESS_TOKEN
    }
  }

  return request(options).then(function() {
    util.log(util.colors.green('Release Notes submitted'));
  });
}

/**
 * @return {!Promise<string>}
 */
function getCurrentSha() {
  return gitExec({ args: 'rev-parse HEAD' }).then(function(sha) {
    return sha.trim();
  });
}

/**
 * @param {!GitMetadataDef} gitMetadata
 * @return {!GitMetadataDef}
 */
function buildChangelog(gitMetadata) {
  var changelog = `## Version: ${argv.version}\n\n`;
  // Append all titles
  changelog += gitMetadata.logs.filter(function(log) {
        var pr = log.pr;
        if (!pr) {
          return true;
        }
        return !pr.filenames.every(function(filename) {
          return config.changelogIgnoreFileTypes.test(filename);
        });
      })
      .map(function(log) {
        var pr = log.pr;
        if (!pr) {
          return '  - ' + log.title;
        }
        return `  - ${pr.title.trim()} (#${pr.id})`;
      }).join('\n');
  changelog += '\n\n## Breakdown by component\n\n';
  var sections = buildSections(gitMetadata);

  Object.keys(sections).sort().forEach(function(section) {
    changelog += `### ${section}\n\n`;
    var uniqueItems = sections[section].filter(function(title, idx) {
      return sections[section].indexOf(title) == idx;
    });
    changelog += uniqueItems.join('');
    changelog += '\n';
  });

  gitMetadata.changelog = changelog;
  return gitMetadata;
}

/**
 * @param {!GitMetadata} gitMetadata
 * @return {!Object<string, string>}
 */
function buildSections(gitMetadata) {
  var sections = {};
  gitMetadata.logs.forEach(function(log) {
    var pr = log.pr;
    if (!pr) {
      return;
    }
    var hasNonDocChange = !pr.filenames.every(function(filename) {
      return config.changelogIgnoreFileTypes.test(filename);
    });
    var listItem = `  - ${pr.title.trim()}\n`;

    if (hasNonDocChange) {
      changelog += listItem;
    }

    pr.filenames.forEach(function(filename) {
      var section;
      var body = '';
      var path = filename.split('/');
      var isExtensionChange = path[0] == 'extensions';
      var isBuiltinChange = path[0] == 'builtins';
      var isAdsChange = path[0] == 'ads';
      // TODO: figure out how to break down validator changes since
      // it is usually a big PR with a number of commits, and the commit
      // message is what is useful for a changelog.
      var isValidatorChange = path[0] == 'validator';

      if (isExtensionChange) {
        section = path[1];
      } else if (isBuiltinChange && isJs(path[1])) {
        // builtins files dont have a nested per component folder.
        section = path[1].replace(/\.js$/, '');
      } else if (isAdsChange && isJs(path[1])) {
        section = 'ads';
      } else if (isValidatorChange) {
        section = 'validator';
      }

      if (section) {
        if (!sections[section]) {
          sections[section] = [];
        }
        // if its the validator section, read the body of the PR
        // and format it correctly under the bullet list.
        if (section == 'validator') {
          body = `\n    ${pr.body.split('\n').join('\n    ')}`;
        }
        sections[section].push(listItem + body);
      }
    });
  });
  return sections;
}

/**
 * Get the latest git tag from either a normal release or from a canary release.
 * @param {!GitMetadataDef} gitMetadata
 * @return {!Promise<GitMetadataDef>}
 */
function getLastGitTag(gitMetadata) {
  var options = {
    args: `describe --abbrev=0 --first-parent --tags ${branch}`
  };
  return gitExec(options).then(function(tag) {
    if (!tag) {
      throw new Error('Could not find latest ' + branch + ' tag.');
    }
    gitMetadata.tag = tag.trim();
    util.log(util.colors.green('Current latest tag: ' + gitMetadata.tag));
    return gitMetadata;
  });
}

/**
 * Runs `git log ${branch}...{tag} --pretty=oneline --first-parent`
 * @param {string} tag
 * @return {!Promise<GitMetadataDef>}
 */
function getGitLog(gitMetadata) {
  var options = {
    args: `log ${branch}...${gitMetadata.tag} --pretty=oneline --first-parent`
  };
  return gitExec(options).then(function(logs) {
    if (!logs) {
      throw new Error('No logs found "git log ' + branch +
          '...' + tag + '".\nIs it possible that there is no delta?\n' +
          'Make sure to fetch and rebase (or reset --hard) the latest ' +
          'from remote upstream.');
    }
    const commits = logs.split('\n').filter(log => !!log.length);
    gitMetadata.logs = commits.map(log => {
      const words = log.split(' ');
      return { sha: words.shift(), title: words.join(' ') };
    });
    return gitMetadata;
  });
}

/**
 * @param {!GitMetadataDef} gitMetadata
 * @return {!Promise<!GitMetadataDef>}
 */
function getGithubPullRequestsMetadata(gitMetadata) {
  // (erwinm): Github seems to only return data for the first 3 pages
  // from my manual testing.
  return BBPromise.all([
      getClosedPullRequests(1),
      getClosedPullRequests(2),
      getClosedPullRequests(3),
  ])
  .then(requests => [].concat.apply([], requests))
  .then(prs => {
    gitMetadata.prs = prs;
    const githubPrRequest = gitMetadata.logs.map(log => {
      const pr = prs.filter(pr => pr.merge_commit_sha == log.sha)[0];
      if (pr) {
        log.pr = buildPrMetadata(pr);
      } else if (isPrIdInTitle(log.title)) {
        const id = getPrIdFromCommit(log.title);
        const prOptions = extend({}, pullOptions);
        prOptions.url += `/${id}`;
        const fileOptions = extend({}, prOptions);
        fileOptions.url += '/files';
        // If we couldn't find the matching pull request from 3 pages
        // of closed pull request try and fetch it through the id
        // if we can retrieve it from the commit message (only available
        // through github merge).
        return getPullRequest(prOptions, log);
      }
      return BBPromise.resolve();
    });
    return BBPromise.all(githubPrRequest).then(() => {
      return gitMetadata;
    });
  });
}

/**
 * We either fetch the pulls/${id}/files but if we have no PrMetadata yet,
 * we will try and also fetch pulls/${id} first before fetching
 * pulls/${id}/files.
 *
 * @param {!GitMetadataDef}
 * @return {!Promise<!GitMetadataDef>}
 */
function getGithubFilesMetadata(gitMetadata) {
  const githubFileRequests = gitMetadata.logs.map(log => {
    if (log.pr) {
      const fileOptions = extend({}, pullOptions);
      fileOptions.url = `${log.pr.url}/files`;
      return getPullRequestFiles(fileOptions, log.pr);
    }
    return BBPromise.resolve();
  });
  return BBPromise.all(githubFileRequests).then(() => {
    return gitMetadata;
  });
}

/**
 * Fetches pulls?page=${opt_page}
 *
 * @param {number=} opt_page
 * @return {!Promise<!Array<!PrMetadataDef>}
 */
function getClosedPullRequests(opt_page) {
  opt_page = opt_page || 1;
  var options = extend({}, pullOptions);
  options.qs = {
    state: 'closed',
    page: opt_page,
    access_token: GITHUB_ACCESS_TOKEN,
  };
  return request(options).then(res => {
    const prs = JSON.parse(res.body);
    assert(Array.isArray(prs), `prs must be an array.`);
    return prs;
  });
}

/**
 * @param {Object<string, string>} prOption
 * @param {!LogMetadataDef} log
 * @return {!Promise<PrMetadataDef>}
 */
function getPullRequest(prOption, log) {
  return request(prOption).then(function(res) {
    var pr = JSON.parse(res.body);
    assert(typeof pr == 'object', 'Pull Requests Metadata must be an object');
    log.pr = buildPrMetadata(pr);
    return log.pr;
  });
}

/**
 * @param {!Object<string, string>} filesOption
 * @param {!PrMetadataDef} pr
 * @return {!Promise<PrMetadataDef>}
 */
function getPullRequestFiles(filesOption, pr) {
  return request(filesOption).then(function(res) {
    var body = JSON.parse(res.body);

    assert(Array.isArray(body) && body.length > 0,
        'Pull request response must not be empty. ' + res.body);
    var filenames = body.map(function(file) {
      return file.filename;
    });

    pr.filenames = filenames;
    return pr;
  });
}

function errHandler(err) {
  var msg = err;
  if (err.message) {
    msg = err.message;
  }
  util.log(util.colors.red(msg));
}

/**
 * Check if the string starts with "Merge pull request #"
 * @param {string} str
 * @return {boolean}
 */
function isPrIdInTitle(str) {
  return str.indexOf('Merge pull request #') == 0;
}

/**
 * @param {string} commit
 * @return {number}
 */
function getPrIdFromCommit(commit) {
  // We only need the PR id
  var id = commit.split(' ')[3].slice(1);
  var value = parseInt(id, 10);
  assert(value > 0, 'Should be an integer greater than 0. ' + value);
  return id;
}

/**
 * Checks if string ends with ".js"
 * @param {string} str
 * @return {boolean}
 */
function isJs(str) {
  return str./*OK*/endsWith('.js');
}

/**
 * @param {!JSONValue} pr
 * @return {!PrMetadata}
 */
function buildPrMetadata(pr) {
  return {
    id: pr.number,
    title: pr.title,
    body: pr.body,
    merge_commit_sha: pr.merge_commit_sha,
    url: pr._links.self.href,
  };
}

gulp.task('changelog', 'Create github release draft', changelog, {
  options: {
    dryrun: '  Generate changelog but dont push it out',
    type: '  Pass in "canary" to generate a canary changelog',
    version: '  The git tag and github release label',
  }
});
<|endoftext|>


<commit_before>import { $$ } from '../dom'
import { Button, StackFill, HorizontalStack, Divider } from '../ui'
import { AnnotationComponent } from '../editor'
import PopoverMixin from './PopoverMixin'
import { getLabel } from './nodeHelpers'

// NOTE: this should be an inline node component
export default class CitationComponent extends PopoverMixin(AnnotationComponent) {
  // If we say that popover is always have delete and edit buttons,
  // then we can move action handlers to mixin
  getActionHandlers () {
    return {
      edit: this._onEdit,
      delete: this._onDelete
    }
  }

  getPopoverComponent () {
    return _CitationPopover
  }

  render () {
    const node = this.props.node
    const el = super.render()
    el.addClass('sc-citation')

    // For now this is just for an inline node emulation
    el.append(
      getLabel(node)
    )

    return el
  }

  exposePopover (selectionState) {
    const { selection, annosByType } = selectionState
    if (selection && selection.isPropertySelection()) {
      const citations = annosByType.get('cite')
      if (citations && citations.length === 1 && citations[0] === this.props.node) {
        return selection.isInsideOf(this.props.node.getSelection())
      }
    }
    return false
  }

  // TODO: this will not work until citation became an inline node
  _onDelete () {
    const { editorSession } = this.context
    const { node } = this.props
    editorSession.executeCommand('remove-citation', { node })
  }

  _onEdit () {
    const { editorSession } = this.context
    const { node } = this.props
    editorSession.executeCommand('edit-citation', { node })
  }
}

function _CitationPopover (props) {
  const references = props.node.resolve('references')

  return $$('div', { class: 'sc-citation-popover' },
    ...references.map(ref => {
      return $$(HorizontalStack, { class: 'se-reference' },
        $$('div', { class: 'se-label' }, `[${ref.label}]`),
        $$('div', { class: 'se-content' }, ref.content)
      )
    }),
    $$(Divider),
    $$(HorizontalStack, {},
      $$('div', { class: 'se-label' }, 'Citation'),
      $$(StackFill),
      $$(Button, { action: 'delete', size: 'small', style: 'danger' }, 'Delete'),
      $$(Button, { action: 'edit', size: 'small', style: 'primary' }, 'Edit')
    )
  )
}
<commit_msg>Let CitationComponent be a regular component.<commit_after>import { $$, Component } from '../dom'
import { Button, StackFill, HorizontalStack, Divider } from '../ui'
import PopoverMixin from './PopoverMixin'
import { getLabel } from './nodeHelpers'

export default class CitationComponent extends PopoverMixin(Component) {
  getActionHandlers () {
    return {
      edit: this._onEdit,
      delete: this._onDelete
    }
  }

  getPopoverComponent () {
    return _CitationPopover
  }

  render () {
    const node = this.props.node
    const el = $$('span').addClass('sc-citation').attr('data-id', node.id)

    const label = getLabel(node) || '???'
    el.append(label)

    return el
  }

  shouldShowPopover (selectionState) {
    const { selection, annosByType } = selectionState
    if (selection && selection.isPropertySelection()) {
      const citations = annosByType.get('cite')
      if (citations && citations.length === 1 && citations[0] === this.props.node) {
        return selection.isInsideOf(this.props.node.getSelection())
      }
    }
    return false
  }

  // TODO: this will not work until citation became an inline node
  _onDelete () {
    const { editorSession } = this.context
    const { node } = this.props
    editorSession.executeCommand('remove-citation', { node })
  }

  _onEdit () {
    const { editorSession } = this.context
    const { node } = this.props
    editorSession.executeCommand('edit-citation', { node })
  }
}

function _CitationPopover (props) {
  const references = props.node.resolve('references')

  return $$('div', { class: 'sc-citation-popover' },
    ...references.map(ref => {
      return $$(HorizontalStack, { class: 'se-reference' },
        $$('div', { class: 'se-label' }, `[${ref.label}]`),
        $$('div', { class: 'se-content' }, ref.content)
      )
    }),
    $$(Divider),
    $$(HorizontalStack, {},
      $$('div', { class: 'se-label' }, 'Citation'),
      $$(StackFill),
      $$(Button, { action: 'delete', size: 'small', style: 'danger' }, 'Delete'),
      $$(Button, { action: 'edit', size: 'small', style: 'primary' }, 'Edit')
    )
  )
}
<|endoftext|>


<commit_before>(function()
{
    'use strict';

    angular
        .module('lumx.search-filter')
        .filter('lxSearchHighlight', lxSearchHighlight)
        .directive('lxSearchFilter', lxSearchFilter);

    lxSearchHighlight.$inject = ['$sce'];

    function lxSearchHighlight($sce)
    {
        function escapeRegexp(queryToEscape)
        {
            return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
        }

        return function (matchItem, query, icon)
        {
            var string = '';

            if (icon)
            {
                string += '';
            }

            string += query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem;

            return $sce.trustAsHtml(string);
        };
    }

    function lxSearchFilter()
    {
        return {
            restrict: 'E',
            templateUrl: 'search-filter.html',
            scope:
            {
                autocomplete: '&?lxAutocomplete',
                closed: '=?lxClosed',
                color: '@?lxColor',
                icon: '@?lxIcon',
                searchOnFocus: '=?lxSearchOnFocus',
                width: '@?lxWidth'
            },
            link: link,
            controller: LxSearchFilterController,
            controllerAs: 'lxSearchFilter',
            bindToController: true,
            replace: true,
            transclude: true
        };

        function link(scope, element, attrs, ctrl, transclude)
        {
            var input;

            attrs.$observe('lxWidth', function(newWidth)
            {
                if (angular.isDefined(scope.lxSearchFilter.closed) && scope.lxSearchFilter.closed)
                {
                    element.find('.search-filter__container').css('width', newWidth);
                }
            });

            transclude(function()
            {
                input = element.find('input');

                ctrl.setInput(input);
                ctrl.setModel(input.data('$ngModelController'));

                input.on('focus', ctrl.focusInput);
                input.on('blur', ctrl.blurInput);
                input.on('keydown', ctrl.keyEvent);
            });

            scope.$on('$destroy', function()
            {
                input.off();
            });
        }
    }

    LxSearchFilterController.$inject = ['$element', '$scope', 'LxDropdownService', 'LxNotificationService', 'LxUtils'];

    function LxSearchFilterController($element, $scope, LxDropdownService, LxNotificationService, LxUtils)
    {
        var lxSearchFilter = this;
        var debouncedAutocomplete;
        var input;
        var itemSelected = false;

        lxSearchFilter.blurInput = blurInput;
        lxSearchFilter.clearInput = clearInput;
        lxSearchFilter.focusInput = focusInput;
        lxSearchFilter.getClass = getClass;
        lxSearchFilter.keyEvent = keyEvent;
        lxSearchFilter.openInput = openInput;
        lxSearchFilter.selectItem = selectItem;
        lxSearchFilter.setInput = setInput;
        lxSearchFilter.setModel = setModel;

        lxSearchFilter.activeChoiceIndex = -1;
        lxSearchFilter.color = angular.isDefined(lxSearchFilter.color) ? lxSearchFilter.color : 'black';
        lxSearchFilter.dropdownId = LxUtils.generateUUID();

        ////////////

        function blurInput()
        {
            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed && !input.val())
            {
                $element.velocity(
                {
                    width: 40
                },
                {
                    duration: 400,
                    easing: 'easeOutQuint',
                    queue: false
                });
            }

            if (!input.val())
            {
                lxSearchFilter.modelController.$setViewValue(undefined);
            }
        }

        function clearInput()
        {
            lxSearchFilter.modelController.$setViewValue(undefined);
            lxSearchFilter.modelController.$render();

            input.focus();
        }

        function focusInput()
        {
            if (!lxSearchFilter.searchOnFocus)
            {
                return;
            }

            updateAutocomplete(lxSearchFilter.modelController.$viewValue, true);
        }

        function getClass()
        {
            var searchFilterClass = [];

            if (angular.isUndefined(lxSearchFilter.closed) || !lxSearchFilter.closed)
            {
                searchFilterClass.push('search-filter--opened-mode');
            }

            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed)
            {
                searchFilterClass.push('search-filter--closed-mode');
            }

            if (input.val())
            {
                searchFilterClass.push('search-filter--has-clear-button');
            }

            if (angular.isDefined(lxSearchFilter.color))
            {
                searchFilterClass.push('search-filter--' + lxSearchFilter.color);
            }

            if (angular.isFunction(lxSearchFilter.autocomplete))
            {
                searchFilterClass.push('search-filter--autocomplete');
            }

            if (LxDropdownService.isOpen(lxSearchFilter.dropdownId))
            {
                searchFilterClass.push('search-filter--is-open');
            }

            return searchFilterClass;
        }

        function keyEvent(_event)
        {
            if (!angular.isFunction(lxSearchFilter.autocomplete))
            {
                return;
            }

            if (!LxDropdownService.isOpen(lxSearchFilter.dropdownId))
            {
                lxSearchFilter.activeChoiceIndex = -1;
            }

            switch (_event.keyCode) {
                case 13:
                    keySelect();
                    if (lxSearchFilter.activeChoiceIndex > -1)
                    {
                        _event.preventDefault();
                    }
                    break;

                case 38:
                    keyUp();
                    _event.preventDefault();
                    break;

                case 40:
                    keyDown();
                    _event.preventDefault();
                    break;
            }

            $scope.$apply();
        }

        function keyDown()
        {
            if (lxSearchFilter.autocompleteList.length)
            {
                lxSearchFilter.activeChoiceIndex += 1;

                if (lxSearchFilter.activeChoiceIndex >= lxSearchFilter.autocompleteList.length)
                {
                    lxSearchFilter.activeChoiceIndex = 0;
                }
            }
        }

        function keySelect()
        {
            if (!lxSearchFilter.autocompleteList || lxSearchFilter.activeChoiceIndex === -1)
            {
                return;
            }

            itemSelected = true;

            LxDropdownService.close(lxSearchFilter.dropdownId);

            lxSearchFilter.modelController.$setViewValue(lxSearchFilter.autocompleteList[lxSearchFilter.activeChoiceIndex]);
            lxSearchFilter.modelController.$render();
        }

        function keyUp()
        {
            if (lxSearchFilter.autocompleteList.length)
            {
                lxSearchFilter.activeChoiceIndex -= 1;

                if (lxSearchFilter.activeChoiceIndex < 0)
                {
                    lxSearchFilter.activeChoiceIndex = lxSearchFilter.autocompleteList.length - 1;
                }
            }
        }

        function onAutocompleteSuccess(autocompleteList)
        {
            lxSearchFilter.autocompleteList = autocompleteList;

            if (lxSearchFilter.autocompleteList.length)
            {
                LxDropdownService.open(lxSearchFilter.dropdownId, $element);
            }
            else
            {
                LxDropdownService.close(lxSearchFilter.dropdownId);
            }
            lxSearchFilter.isLoading = false;
        }

        function onAutocompleteError(error)
        {
            LxNotificationService.error(error);
            lxSearchFilter.isLoading = false;
        }

        function openInput()
        {
            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed)
            {
                $element.velocity(
                {
                    width: angular.isDefined(lxSearchFilter.width) ? parseInt(lxSearchFilter.width) : 240
                },
                {
                    duration: 400,
                    easing: 'easeOutQuint',
                    queue: false,
                    complete: function()
                    {
                        input.focus();
                    }
                });
            }
            else
            {
                input.focus();
            }
        }

        function selectItem(_item)
        {
            itemSelected = true;

            lxSearchFilter.modelController.$setViewValue(_item);
            lxSearchFilter.modelController.$render();
        }

        function setInput(_input)
        {
            input = _input;
        }

        function setModel(_modelController)
        {
            lxSearchFilter.modelController = _modelController;

            if (angular.isFunction(lxSearchFilter.autocomplete) && angular.isFunction(lxSearchFilter.autocomplete()))
            {
                debouncedAutocomplete = LxUtils.debounce(function()
                {
                    lxSearchFilter.isLoading = true;
                    (lxSearchFilter.autocomplete()).apply(this, arguments);
                }, 500);
                lxSearchFilter.modelController.$parsers.push(updateAutocomplete);
            }
        }

        function updateAutocomplete(_newValue, _immediate)
        {
            if ((_newValue || (angular.isUndefined(_newValue) && lxSearchFilter.searchOnFocus)) && !itemSelected)
            {
                if (_immediate)
                {
                    lxSearchFilter.isLoading = true;
                    (lxSearchFilter.autocomplete()).apply(this, [_newValue, onAutocompleteSuccess, onAutocompleteError]);
                }
                else
                {
                    debouncedAutocomplete(_newValue, onAutocompleteSuccess, onAutocompleteError);
                }
            }
            else
            {
                debouncedAutocomplete.clear();
                LxDropdownService.close(lxSearchFilter.dropdownId);
            }

            itemSelected = false;

            return _newValue;
        }
    }
})();<commit_msg>Fix search-filter: avoid linter error<commit_after>(function()
{
    'use strict';

    angular
        .module('lumx.search-filter')
        .filter('lxSearchHighlight', lxSearchHighlight)
        .directive('lxSearchFilter', lxSearchFilter);

    lxSearchHighlight.$inject = ['$sce'];

    function lxSearchHighlight($sce)
    {
        function escapeRegexp(queryToEscape)
        {
            return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
        }

        return function (matchItem, query, icon)
        {
            var string = '';

            if (icon)
            {
                string += '';
            }

            string += query && matchItem ? matchItem.replace(new RegExp(escapeRegexp(query), 'gi'), '$&') : matchItem;

            return $sce.trustAsHtml(string);
        };
    }

    function lxSearchFilter()
    {
        return {
            restrict: 'E',
            templateUrl: 'search-filter.html',
            scope:
            {
                autocomplete: '&?lxAutocomplete',
                closed: '=?lxClosed',
                color: '@?lxColor',
                icon: '@?lxIcon',
                searchOnFocus: '=?lxSearchOnFocus',
                width: '@?lxWidth'
            },
            link: link,
            controller: LxSearchFilterController,
            controllerAs: 'lxSearchFilter',
            bindToController: true,
            replace: true,
            transclude: true
        };

        function link(scope, element, attrs, ctrl, transclude)
        {
            var input;

            attrs.$observe('lxWidth', function(newWidth)
            {
                if (angular.isDefined(scope.lxSearchFilter.closed) && scope.lxSearchFilter.closed)
                {
                    element.find('.search-filter__container').css('width', newWidth);
                }
            });

            transclude(function()
            {
                input = element.find('input');

                ctrl.setInput(input);
                ctrl.setModel(input.data('$ngModelController'));

                input.on('focus', ctrl.focusInput);
                input.on('blur', ctrl.blurInput);
                input.on('keydown', ctrl.keyEvent);
            });

            scope.$on('$destroy', function()
            {
                input.off();
            });
        }
    }

    LxSearchFilterController.$inject = ['$element', '$scope', 'LxDropdownService', 'LxNotificationService', 'LxUtils'];

    function LxSearchFilterController($element, $scope, LxDropdownService, LxNotificationService, LxUtils)
    {
        var lxSearchFilter = this;
        var debouncedAutocomplete;
        var input;
        var itemSelected = false;

        lxSearchFilter.blurInput = blurInput;
        lxSearchFilter.clearInput = clearInput;
        lxSearchFilter.focusInput = focusInput;
        lxSearchFilter.getClass = getClass;
        lxSearchFilter.keyEvent = keyEvent;
        lxSearchFilter.openInput = openInput;
        lxSearchFilter.selectItem = selectItem;
        lxSearchFilter.setInput = setInput;
        lxSearchFilter.setModel = setModel;

        lxSearchFilter.activeChoiceIndex = -1;
        lxSearchFilter.color = angular.isDefined(lxSearchFilter.color) ? lxSearchFilter.color : 'black';
        lxSearchFilter.dropdownId = LxUtils.generateUUID();

        ////////////

        function blurInput()
        {
            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed && !input.val())
            {
                $element.velocity(
                {
                    width: 40
                },
                {
                    duration: 400,
                    easing: 'easeOutQuint',
                    queue: false
                });
            }

            if (!input.val())
            {
                lxSearchFilter.modelController.$setViewValue(undefined);
            }
        }

        function clearInput()
        {
            lxSearchFilter.modelController.$setViewValue(undefined);
            lxSearchFilter.modelController.$render();

            input.focus();
        }

        function focusInput()
        {
            if (!lxSearchFilter.searchOnFocus)
            {
                return;
            }

            updateAutocomplete(lxSearchFilter.modelController.$viewValue, true);
        }

        function getClass()
        {
            var searchFilterClass = [];

            if (angular.isUndefined(lxSearchFilter.closed) || !lxSearchFilter.closed)
            {
                searchFilterClass.push('search-filter--opened-mode');
            }

            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed)
            {
                searchFilterClass.push('search-filter--closed-mode');
            }

            if (input.val())
            {
                searchFilterClass.push('search-filter--has-clear-button');
            }

            if (angular.isDefined(lxSearchFilter.color))
            {
                searchFilterClass.push('search-filter--' + lxSearchFilter.color);
            }

            if (angular.isFunction(lxSearchFilter.autocomplete))
            {
                searchFilterClass.push('search-filter--autocomplete');
            }

            if (LxDropdownService.isOpen(lxSearchFilter.dropdownId))
            {
                searchFilterClass.push('search-filter--is-open');
            }

            return searchFilterClass;
        }

        function keyEvent(_event)
        {
            if (!angular.isFunction(lxSearchFilter.autocomplete))
            {
                return;
            }

            if (!LxDropdownService.isOpen(lxSearchFilter.dropdownId))
            {
                lxSearchFilter.activeChoiceIndex = -1;
            }

            switch (_event.keyCode) {
                case 13:
                    keySelect();
                    if (lxSearchFilter.activeChoiceIndex > -1)
                    {
                        _event.preventDefault();
                    }
                    break;

                case 38:
                    keyUp();
                    _event.preventDefault();
                    break;

                case 40:
                    keyDown();
                    _event.preventDefault();
                    break;
            }

            $scope.$apply();
        }

        function keyDown()
        {
            if (lxSearchFilter.autocompleteList.length)
            {
                lxSearchFilter.activeChoiceIndex += 1;

                if (lxSearchFilter.activeChoiceIndex >= lxSearchFilter.autocompleteList.length)
                {
                    lxSearchFilter.activeChoiceIndex = 0;
                }
            }
        }

        function keySelect()
        {
            if (!lxSearchFilter.autocompleteList || lxSearchFilter.activeChoiceIndex === -1)
            {
                return;
            }

            itemSelected = true;

            LxDropdownService.close(lxSearchFilter.dropdownId);

            lxSearchFilter.modelController.$setViewValue(lxSearchFilter.autocompleteList[lxSearchFilter.activeChoiceIndex]);
            lxSearchFilter.modelController.$render();
        }

        function keyUp()
        {
            if (lxSearchFilter.autocompleteList.length)
            {
                lxSearchFilter.activeChoiceIndex -= 1;

                if (lxSearchFilter.activeChoiceIndex < 0)
                {
                    lxSearchFilter.activeChoiceIndex = lxSearchFilter.autocompleteList.length - 1;
                }
            }
        }

        function onAutocompleteSuccess(autocompleteList)
        {
            lxSearchFilter.autocompleteList = autocompleteList;

            if (lxSearchFilter.autocompleteList.length)
            {
                LxDropdownService.open(lxSearchFilter.dropdownId, $element);
            }
            else
            {
                LxDropdownService.close(lxSearchFilter.dropdownId);
            }
            lxSearchFilter.isLoading = false;
        }

        function onAutocompleteError(error)
        {
            LxNotificationService.error(error);
            lxSearchFilter.isLoading = false;
        }

        function openInput()
        {
            if (angular.isDefined(lxSearchFilter.closed) && lxSearchFilter.closed)
            {
                $element.velocity(
                {
                    width: angular.isDefined(lxSearchFilter.width) ? parseInt(lxSearchFilter.width) : 240
                },
                {
                    duration: 400,
                    easing: 'easeOutQuint',
                    queue: false,
                    complete: function()
                    {
                        input.focus();
                    }
                });
            }
            else
            {
                input.focus();
            }
        }

        function selectItem(_item)
        {
            itemSelected = true;

            lxSearchFilter.modelController.$setViewValue(_item);
            lxSearchFilter.modelController.$render();
        }

        function setInput(_input)
        {
            input = _input;
        }

        function setModel(_modelController)
        {
            lxSearchFilter.modelController = _modelController;

            if (angular.isFunction(lxSearchFilter.autocomplete) && angular.isFunction(lxSearchFilter.autocomplete()))
            {
                debouncedAutocomplete = LxUtils.debounce(function()
                {
                    lxSearchFilter.isLoading = true;
                    (lxSearchFilter.autocomplete()).apply(this, arguments);
                }, 500);
                lxSearchFilter.modelController.$parsers.push(updateAutocomplete);
            }
        }

        function updateAutocomplete(_newValue, _immediate)
        {
            if ((_newValue || (angular.isUndefined(_newValue) && lxSearchFilter.searchOnFocus)) && !itemSelected)
            {
                if (_immediate)
                {
                    lxSearchFilter.isLoading = true;
                    (lxSearchFilter.autocomplete())(_newValue, onAutocompleteSuccess, onAutocompleteError);
                }
                else
                {
                    debouncedAutocomplete(_newValue, onAutocompleteSuccess, onAutocompleteError);
                }
            }
            else
            {
                debouncedAutocomplete.clear();
                LxDropdownService.close(lxSearchFilter.dropdownId);
            }

            itemSelected = false;

            return _newValue;
        }
    }
})();<|endoftext|>


<commit_before>/* Core partition rebalance algorithms, no UI. */

function rebalanceMap(ctx, req) {
  return run(ctx, req,
             initPartitionModel,
             validatePartitionSettings,
             allocNextMap,
             planNextMap,
             validateNextMap);
}

function validatePartitionSettings(ctx, req) {
  req.nextBucketEvents = _.clone(req.prevBucketEvents);
  req.nextBucketEvents.events = sortDesc(req.nextBucketEvents.events || [], "when");

  req.lastPartitionParams = _.findWhere(req.nextBucketEvents.events,
                                        { class: "partitionParams" });
  if (req.lastPartitionParams) {
    req.err = _.reduce(["keyFunc", "model", "numPartitions"], function(r, k) {
        if (req.lastPartitionParams[k] != req.wantPartitionParams[k]) {
          return "partitionParams." + k + " not equal: " +
            req.lastPartitionParams[k] + " vs " + req.wantPartitionParams[k];
        }
        return r;
      }, null);
    if (req.err) {
      return;
    }
  }

  req.lastPartitionMap = _.findWhere(req.nextBucketEvents.events,
                                     { class: "partitionMap" });
  if (req.lastPartitionMap) {
    req.lastPartitions = partitionsWithNodeNames(req.lastPartitionMap.partitions,
                                                 req.lastPartitionMap.nodes);
  }

  req.deltaNodes = { added: _.difference(req.wantPartitionParams.nodes,
                                         (req.lastPartitionParams || {}).nodes),
                     removed: _.difference((req.lastPartitionParams || {}).nodes,
                                           req.wantPartitionParams.nodes) };
}

function allocNextMap(ctx, req) {
  req.nextPartitionMap =
    ctx.newObj("partitionMap", _.omit(req.wantPartitionParams, "class")).result;
  req.nextPartitionMap.partitions =
    keyFunc[req.wantPartitionParams.keyFunc].allocPartitions(req);
  req.nextPartitionMapNumPartitions =
    _.size(req.nextPartitionMap.partitions);
}

function planNextMap(ctx, req) {
  // Start by filling out nextPartitions same as lastPartitions, but
  // filter out the to-be-removed nodes.
  var lastPartitions = req.lastPartitions || {};
  var nextPartitions =
    _.object(_.map(req.nextPartitionMap.partitions, function(_, partitionId) {
          var lastPartition = lastPartitions[partitionId] || {};
          var nextPartition = removeNodesFromPartition(lastPartition,
                                                       req.deltaNodes.removed);
          return [partitionId, nextPartition];
        }));

  req.stateNodeCounts = countStateNodes(nextPartitions);
  req.hierarchy = req.nextPartitionMap.hierarchy;
  req.hierarchyRules = req.nextPartitionMap.hierarchyRules || {};
  req.hierarchyChildren = mapParentsToMapChildren(req.hierarchy);
  var zeroes = "00000000000";

  // Run through the sorted partition states (master, slave, etc) that
  // have constraints and invoke assignStateToPartitions().
  _.each(req.partitionModelStates, function(s) {
      var constraints =
        parseInt((req.wantPartitionParams.constraints || {})[s.name]) ||
        parseInt(s.constraints) || 0;
      if (constraints >= 0) {
        assignStateToPartitions(s.name, constraints);
      }
    });

  // Given a state and its constraints, for every partition, assign nodes.
  function assignStateToPartitions(state, constraints) {
    // Sort the partitions to help reach a better assignment.
    var partitionIds =
      _.sortBy(_.keys(nextPartitions).sort(), function(partitionId) {
          var suffix = partitionId;
          if (partitionId == String(parseInt(partitionId))) {
            suffix = zeroes.slice(0, zeroes.length - partitionId.length) + partitionId;
          }
          var partitionIdInt = parseInt(partitionId);
          // First, favor partitions on nodes that are to-be-removed.
          var lastPartition = lastPartitions[partitionId] || {};
          if (!_.isEmpty(_.intersection(lastPartition[state],
                                        req.deltaNodes.removed))) {
            return 0 + suffix;
          }
          // Then, favor partitions who haven't been assigned to any
          // newly added nodes yet for any state.
          if (_.isEmpty(_.intersection(_.flatten(_.values(nextPartitions[partitionId])),
                                       req.deltaNodes.added))) {
            return 1 + suffix;
          }
          return 2 + suffix;
        });

    // Key is higherPriorityNode, val is { lowerPriorityNode: count }.
    req.nodeToNodeCounts = {};

    nextPartitions =
      _.object(_.map(partitionIds, function(partitionId) {
            var partition = nextPartitions[partitionId];
            var nodesToAssign = findBestNodes(partitionId, partition,
                                              state, constraints);
            partition = removeNodesFromPartition(partition,
                                                 partition[state],
                                                 decStateNodeCounts);
            partition = removeNodesFromPartition(partition,
                                                 nodesToAssign,
                                                 decStateNodeCounts);
            partition[state] = nodesToAssign;
            incStateNodeCounts(state, nodesToAssign);
            return [partitionId, partition];
          }));
  }

  function findBestNodes(partitionId, partition, state, constraints) {
    var weights = req.nextPartitionMap.weights || {};
    var stickiness = (req.stickiness || {})[state] || 1.5;
    var statePriority = req.mapState[state].priority;
    var stateNodeCounts =
      req.stateNodeCounts[state] =
      req.stateNodeCounts[state] || {};
    var nodePartitionCounts =
      _.reduce(req.stateNodeCounts, function(r, nodeCounts) {
          _.each(nodeCounts, function(count, node) {
              r[node] = (r[node] || 0) + count;
            });
          return r;
        }, {});
    var highestPriorityState = req.partitionModelStates[0].name;
    var highestPriorityNode = _.first(partition[highestPriorityState]);

    var candidateNodes =
      _.sortBy(excludeHigherPriorityNodes(req.nextPartitionMap.nodes),
               scoreNode);

    var hierarchyNodes = [];
    _.each(req.hierarchyRules[state], function(stateHierarchyRule) {
        var hierarchyCandidates =
          includeExcludeNodes(highestPriorityNode || hierarchyNodes[0],
                              stateHierarchyRule,
                              req.hierarchy,
                              req.hierarchyChildren);
        hierarchyCandidates =
          _.sortBy(excludeHigherPriorityNodes(_.intersection(hierarchyCandidates,
                                                             req.nextPartitionMap.nodes)),
                   scoreNode);
        hierarchyNodes.push(_.first(hierarchyCandidates) || candidateNodes[0]);
      });

    candidateNodes = _.uniq(hierarchyNodes.concat(candidateNodes));
    candidateNodes = candidateNodes.slice(0, constraints);
    if (candidateNodes.length < constraints) {
      req.warnings.push("warning: could not meet constraints: " + constraints +
                        ", state: " + state +
                        ", partitionId: " + partitionId);
    }

    _.each(candidateNodes, function(candidateNode) {
        var m = req.nodeToNodeCounts[highestPriorityNode] =
          req.nodeToNodeCounts[highestPriorityNode] || {};
        m[candidateNode] = (m[candidateNode] || 0) + 1;
      });

    return candidateNodes;

    function excludeHigherPriorityNodes(nodes) {
      // Filter out nodes of a higher priority state; e.g., if
      // we're assigning slaves, leave the masters untouched.
      _.each(partition, function(sNodes, state) {
          if (req.mapState[state].priority > statePriority) {
            nodes = _.difference(nodes, sNodes);
          }
        });
      return nodes;
    }

    function scoreNode(node) {
      var numPartitions = req.nextPartitionMapNumPartitions * 1.0;
      var lowerPriorityBalanceFactor =
        ((req.nodeToNodeCounts[highestPriorityNode] || {})[node] || 0) /
        numPartitions;
      var filledFactor =
        0.001 * (nodePartitionCounts[node] || 0) /
        numPartitions;
      var currentFactor = _.contains(partition[state], node) ? stickiness : 0;

      var r = stateNodeCounts[node] || 0;
      r = r + lowerPriorityBalanceFactor;
      r = r + filledFactor;
      var w = weights[node] || 0;
      if (w > 0) {
        r = r / (1.0 * w);
      }
      r = r - currentFactor;
      return r;
    }
  }

  function incStateNodeCounts(state, nodes) {
    adjustStateNodeCounts(req.stateNodeCounts, state, nodes, 1);
  }
  function decStateNodeCounts(state, nodes) {
    adjustStateNodeCounts(req.stateNodeCounts, state, nodes, -1);
  }
  function adjustStateNodeCounts(stateNodeCounts, state, nodes, amt) {
    _.each(nodes, function(n) {
        var s = stateNodeCounts[state] = stateNodeCounts[state] || {};
        s[n] = (s[n] || 0) + amt;
        if (s[n] < 0 || s[n] > req.nextPartitionMapNumPartitions) {
          console.log("ERROR: adjustStateNodeCounts out of range" +
                      ", state: " + state + " node: " + n + " s[n]: " + s[n]);
        }
      });
  }

  req.nextPartitionMap.partitions = nextPartitions;
  req.nextPartitionMap.partitions =
    partitionsWithNodeIndexes(req.nextPartitionMap.partitions,
                              req.nextPartitionMap.nodes);
}

function validateNextMap(ctx, req) {
  // TODO: do real validation here.
  req.nextBucketEvents.events.unshift(req.wantPartitionParams);
  req.nextBucketEvents.events.unshift(req.nextPartitionMap);
}

// Example, with partitions of...
//   { "0": { "master": ["a"], "slave": ["b", "c"] } },
//   { "1": { "master": ["b"], "slave": ["c"] } }
// then return value will be...
//   { "master": { "a": 1, "b": 1 } },
//   { "slave": { "b": 1, "c": 2 } }
function countStateNodes(partitions) {
  return _.reduce(partitions, function(r, partition, partitionId) {
      return _.reduce(partition, function(r, nodes, state) {
          _.each(nodes, function(node) {
              var s = r[state] = r[state] || {};
              s[node] = (s[node] || 0) + 1;
            });
          return r;
        }, r);
    }, {});
}
<commit_msg>Remove dead code.<commit_after>/* Core partition rebalance algorithms, no UI. */

function rebalanceMap(ctx, req) {
  return run(ctx, req,
             initPartitionModel,
             validatePartitionSettings,
             allocNextMap,
             planNextMap,
             validateNextMap);
}

function validatePartitionSettings(ctx, req) {
  req.nextBucketEvents = _.clone(req.prevBucketEvents);
  req.nextBucketEvents.events = sortDesc(req.nextBucketEvents.events || [], "when");

  req.lastPartitionParams = _.findWhere(req.nextBucketEvents.events,
                                        { class: "partitionParams" });
  if (req.lastPartitionParams) {
    req.err = _.reduce(["keyFunc", "model", "numPartitions"], function(r, k) {
        if (req.lastPartitionParams[k] != req.wantPartitionParams[k]) {
          return "partitionParams." + k + " not equal: " +
            req.lastPartitionParams[k] + " vs " + req.wantPartitionParams[k];
        }
        return r;
      }, null);
    if (req.err) {
      return;
    }
  }

  req.lastPartitionMap = _.findWhere(req.nextBucketEvents.events,
                                     { class: "partitionMap" });
  if (req.lastPartitionMap) {
    req.lastPartitions = partitionsWithNodeNames(req.lastPartitionMap.partitions,
                                                 req.lastPartitionMap.nodes);
  }

  req.deltaNodes = { added: _.difference(req.wantPartitionParams.nodes,
                                         (req.lastPartitionParams || {}).nodes),
                     removed: _.difference((req.lastPartitionParams || {}).nodes,
                                           req.wantPartitionParams.nodes) };
}

function allocNextMap(ctx, req) {
  req.nextPartitionMap =
    ctx.newObj("partitionMap", _.omit(req.wantPartitionParams, "class")).result;
  req.nextPartitionMap.partitions =
    keyFunc[req.wantPartitionParams.keyFunc].allocPartitions(req);
  req.nextPartitionMapNumPartitions =
    _.size(req.nextPartitionMap.partitions);
}

function planNextMap(ctx, req) {
  // Start by filling out nextPartitions same as lastPartitions, but
  // filter out the to-be-removed nodes.
  var lastPartitions = req.lastPartitions || {};
  var nextPartitions =
    _.object(_.map(req.nextPartitionMap.partitions, function(_, partitionId) {
          var lastPartition = lastPartitions[partitionId] || {};
          var nextPartition = removeNodesFromPartition(lastPartition,
                                                       req.deltaNodes.removed);
          return [partitionId, nextPartition];
        }));

  req.stateNodeCounts = countStateNodes(nextPartitions);
  req.hierarchy = req.nextPartitionMap.hierarchy;
  req.hierarchyRules = req.nextPartitionMap.hierarchyRules || {};
  req.hierarchyChildren = mapParentsToMapChildren(req.hierarchy);
  var zeroes = "00000000000";

  // Run through the sorted partition states (master, slave, etc) that
  // have constraints and invoke assignStateToPartitions().
  _.each(req.partitionModelStates, function(s) {
      var constraints =
        parseInt((req.wantPartitionParams.constraints || {})[s.name]) ||
        parseInt(s.constraints) || 0;
      if (constraints >= 0) {
        assignStateToPartitions(s.name, constraints);
      }
    });

  // Given a state and its constraints, for every partition, assign nodes.
  function assignStateToPartitions(state, constraints) {
    // Sort the partitions to help reach a better assignment.
    var partitionIds =
      _.sortBy(_.keys(nextPartitions).sort(), function(partitionId) {
          var suffix = partitionId;
          if (partitionId == String(parseInt(partitionId))) {
            suffix = zeroes.slice(0, zeroes.length - partitionId.length) + partitionId;
          }
          // First, favor partitions on nodes that are to-be-removed.
          var lastPartition = lastPartitions[partitionId] || {};
          if (!_.isEmpty(_.intersection(lastPartition[state],
                                        req.deltaNodes.removed))) {
            return 0 + suffix;
          }
          // Then, favor partitions who haven't been assigned to any
          // newly added nodes yet for any state.
          if (_.isEmpty(_.intersection(_.flatten(_.values(nextPartitions[partitionId])),
                                       req.deltaNodes.added))) {
            return 1 + suffix;
          }
          return 2 + suffix;
        });

    // Key is higherPriorityNode, val is { lowerPriorityNode: count }.
    req.nodeToNodeCounts = {};

    nextPartitions =
      _.object(_.map(partitionIds, function(partitionId) {
            var partition = nextPartitions[partitionId];
            var nodesToAssign = findBestNodes(partitionId, partition,
                                              state, constraints);
            partition = removeNodesFromPartition(partition,
                                                 partition[state],
                                                 decStateNodeCounts);
            partition = removeNodesFromPartition(partition,
                                                 nodesToAssign,
                                                 decStateNodeCounts);
            partition[state] = nodesToAssign;
            incStateNodeCounts(state, nodesToAssign);
            return [partitionId, partition];
          }));
  }

  function findBestNodes(partitionId, partition, state, constraints) {
    var weights = req.nextPartitionMap.weights || {};
    var stickiness = (req.stickiness || {})[state] || 1.5;
    var statePriority = req.mapState[state].priority;
    var stateNodeCounts =
      req.stateNodeCounts[state] =
      req.stateNodeCounts[state] || {};
    var nodePartitionCounts =
      _.reduce(req.stateNodeCounts, function(r, nodeCounts) {
          _.each(nodeCounts, function(count, node) {
              r[node] = (r[node] || 0) + count;
            });
          return r;
        }, {});
    var highestPriorityState = req.partitionModelStates[0].name;
    var highestPriorityNode = _.first(partition[highestPriorityState]);

    var candidateNodes =
      _.sortBy(excludeHigherPriorityNodes(req.nextPartitionMap.nodes),
               scoreNode);

    var hierarchyNodes = [];
    _.each(req.hierarchyRules[state], function(stateHierarchyRule) {
        var hierarchyCandidates =
          includeExcludeNodes(highestPriorityNode || hierarchyNodes[0],
                              stateHierarchyRule,
                              req.hierarchy,
                              req.hierarchyChildren);
        hierarchyCandidates =
          _.sortBy(excludeHigherPriorityNodes(_.intersection(hierarchyCandidates,
                                                             req.nextPartitionMap.nodes)),
                   scoreNode);
        hierarchyNodes.push(_.first(hierarchyCandidates) || candidateNodes[0]);
      });

    candidateNodes = _.uniq(hierarchyNodes.concat(candidateNodes));
    candidateNodes = candidateNodes.slice(0, constraints);
    if (candidateNodes.length < constraints) {
      req.warnings.push("warning: could not meet constraints: " + constraints +
                        ", state: " + state +
                        ", partitionId: " + partitionId);
    }

    _.each(candidateNodes, function(candidateNode) {
        var m = req.nodeToNodeCounts[highestPriorityNode] =
          req.nodeToNodeCounts[highestPriorityNode] || {};
        m[candidateNode] = (m[candidateNode] || 0) + 1;
      });

    return candidateNodes;

    function excludeHigherPriorityNodes(nodes) {
      // Filter out nodes of a higher priority state; e.g., if
      // we're assigning slaves, leave the masters untouched.
      _.each(partition, function(sNodes, state) {
          if (req.mapState[state].priority > statePriority) {
            nodes = _.difference(nodes, sNodes);
          }
        });
      return nodes;
    }

    function scoreNode(node) {
      var numPartitions = req.nextPartitionMapNumPartitions * 1.0;
      var lowerPriorityBalanceFactor =
        ((req.nodeToNodeCounts[highestPriorityNode] || {})[node] || 0) /
        numPartitions;
      var filledFactor =
        0.001 * (nodePartitionCounts[node] || 0) /
        numPartitions;
      var currentFactor = _.contains(partition[state], node) ? stickiness : 0;

      var r = stateNodeCounts[node] || 0;
      r = r + lowerPriorityBalanceFactor;
      r = r + filledFactor;
      var w = weights[node] || 0;
      if (w > 0) {
        r = r / (1.0 * w);
      }
      r = r - currentFactor;
      return r;
    }
  }

  function incStateNodeCounts(state, nodes) {
    adjustStateNodeCounts(req.stateNodeCounts, state, nodes, 1);
  }
  function decStateNodeCounts(state, nodes) {
    adjustStateNodeCounts(req.stateNodeCounts, state, nodes, -1);
  }
  function adjustStateNodeCounts(stateNodeCounts, state, nodes, amt) {
    _.each(nodes, function(n) {
        var s = stateNodeCounts[state] = stateNodeCounts[state] || {};
        s[n] = (s[n] || 0) + amt;
        if (s[n] < 0 || s[n] > req.nextPartitionMapNumPartitions) {
          console.log("ERROR: adjustStateNodeCounts out of range" +
                      ", state: " + state + " node: " + n + " s[n]: " + s[n]);
        }
      });
  }

  req.nextPartitionMap.partitions = nextPartitions;
  req.nextPartitionMap.partitions =
    partitionsWithNodeIndexes(req.nextPartitionMap.partitions,
                              req.nextPartitionMap.nodes);
}

function validateNextMap(ctx, req) {
  // TODO: do real validation here.
  req.nextBucketEvents.events.unshift(req.wantPartitionParams);
  req.nextBucketEvents.events.unshift(req.nextPartitionMap);
}

// Example, with partitions of...
//   { "0": { "master": ["a"], "slave": ["b", "c"] } },
//   { "1": { "master": ["b"], "slave": ["c"] } }
// then return value will be...
//   { "master": { "a": 1, "b": 1 } },
//   { "slave": { "b": 1, "c": 2 } }
function countStateNodes(partitions) {
  return _.reduce(partitions, function(r, partition, partitionId) {
      return _.reduce(partition, function(r, nodes, state) {
          _.each(nodes, function(node) {
              var s = r[state] = r[state] || {};
              s[node] = (s[node] || 0) + 1;
            });
          return r;
        }, r);
    }, {});
}
<|endoftext|>


<commit_before>var lineCount = 0;
var initialized = false;
var isHoliday = false;
var turn = 0;

var readline = require('readline'),
rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt("");
console.log('READY');
rl.prompt();
rl.on('line', function (line) {
	lineCount++;
	if(lineCount == 2 && !initialized) {
		initialized = true;
		lineCount = 0;
	} else if(!isHoliday && lineCount == 11) {
		dateWeekday();
		isHoliday = true;
		lineCount = 0;
		turn++;
	} else if(isHoliday && lineCount == 10) {
		dateHoliday();
		isHoliday = false;
		lineCount = 0;
		turn++;
	}
	if(turn < 10) {
		rl.prompt();
	}
});

function dateWeekday() {
	console.log('0 1 0 1 0');
}

function dateHoliday() {
	console.log('1 0');
}<commit_msg>Modify javascript AI to random walk.<commit_after>var lineCount = 0;
var initialized = false;
var isHoliday = false;
var turn = 0;
var T, P, H, E, L, R, B;

var readline = require('readline'),
rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt("");
console.log('READY');
rl.prompt();
rl.on('line', function (line) {
	lineCount++;

	if(!initialized) {
		if(lineCount == 1) {
			var values = line.split(' ');
			T = values[0], P = values[1], H = values[2];
			E = new Array(H);
		} else if(lineCount == 2) {
			var values = line.split(' ');
			for(var i = 0; i < H; i++) {
				E[i] = values[i];
			}
			initialized = true;
		}
	} else {
		if(lineCount == 1) {

		} else if(2 <= lineCount && lineCount <= 9 ) {
			var values = line.split(' ');
		} else if(lineCount == 10) {
			if(!isHoliday) {
				var values = line.split(' ');
			} else {
				dateHoliday();
				lineCount = 0;
				isHoliday = false;
				turn++;
			}
		} else {
			dateWeekday();
			lineCount = 0;
			isHoliday = true;
			turn++;
		}
	}
	if(turn < 10) {
		rl.prompt();
	} else {
		rl.close();
	}
});

function dateWeekday() {
	var message = ""
	for(var i = 0; i < 4; i++) {
		var num = randomNumber();
		message += num;
		message += ' ';
	}
	message += randomNumber();
	console.log(message);
}

function dateHoliday() {
	var message = ""
	message += randomNumber();
	message += ' ';
	message += randomNumber();
	console.log(message);
}

function randomNumber() {
	return Math.floor(Math.random() * H);
}<|endoftext|>


<commit_before>// All webpack assets in development will be loaded via webpack dev server

// turbolinks comes from npm and is listed in webpack.client.base.config.js

//= require bootstrap

//= require es5-shim/es5-shim

//= require select2
//= require custom

//= require tabslet.js

//= require jquery.turbolinks
<commit_msg>Reverting accidental commit<commit_after>// All webpack assets in development will be loaded via webpack dev server

// turbolinks comes from npm and is listed in webpack.client.base.config.js

//= require bootstrap

//= require es5-shim/es5-shim

//= require select2
//= require custom

//= require tabslet.js

//= require jquery.turbolinks
//= require jquery-fileupload/basic

<|endoftext|>


<commit_before>$(document).ready(function () {
var markers_gprs = [];
var markers_aprs = [];
var markers_telemetry = [];
var markers_Oleg = [];
var id_gprs = 0;
var id_aprs = 0;
var id_telemetry = 0;

var url = 'http://' + document.domain + ':' + location.port;
var socket = io.connect(url + "/mcc");
	socket.on('connect', function() {
		socket.emit('last_dots');
	});
socket.emit('Oleg');

socket.on('lastMarkerOleg', function (msg) {
	setTimeout(function(){
		try{
		    var gprs = msg['Oleg'];
		    var json = JSON.parse(gprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_Oleg,'----',1);
		    })
		} catch {console.log("Не удалось взять данные с трекера");}
            socket.emit('Oleg');
}, 60000);
});

socket.on('lastMarkers', function (msg) {

		var gprs = msg['gprs'];
		try{
		    var json = JSON.parse(gprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_gprs,'gprs',9);
		    })
		}catch{console.log("Не удалось взять последние точки gprs");}

		var aprs = msg['aprs'];
		try{

            var json = JSON.parse(aprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_aprs,'aprs',9);
		    })
		}catch{console.log("Не удалось взять последние точки aprs");}

		var telemetry = msg['telemetry'];
		try{

		    var json = JSON.parse(telemetry);

		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_telemetry,'telemetry',9);
		    })
	}catch{console.log("Не удалось взять последние точки телеметрии");}

})
socket.emit('my_event',{data: 0});
k=0;
i =0;
socket.on('gprs', function (msg) {
	if (i==0){
		GPRS(msg,markers_gprs);
		i=1;
		 }
	else	{
			setTimeout(function(){
	  		GPRS(msg,markers_gprs);
			}, 5000);
		}

});

n=0
socket.emit('my_event2',{data: 0});
socket.on('aprs', function (msg) {
	if (n==0){
		APRS(msg,markers_aprs);
		n=1;
	}
	else	{
			setTimeout(function(){
	  		APRS(msg,markers_aprs);
			}, 10000);
		}
});

g=0
socket.emit('my_event3',{data: 0});

socket.on('telemetry', function (msg) {
	if (g==0){
  		TELEMETRY(msg,markers_telemetry);
		g=1;
	}
	else	{
			setTimeout(function(){
	  		TELEMETRY(msg,markers_telemetry);
			}, 10000);
		}
});

$("#telemetry").change(function(){
	if($("#telemetry").prop("checked")){changeMarkers(map,markers_telemetry)}
	else {changeMarkers(null,markers_telemetry)} });
$("#gprs").change(function(){
	if($("#gprs").prop("checked")){changeMarkers(map,markers_gprs)}
	else  {changeMarkers(null,markers_gprs)}});
$("#aprs").change(function(){
	if($("#aprs").prop("checked")) {changeMarkers(map,markers_aprs)}
	else {changeMarkers(null,markers_aprs)} });

function APRS(msg,markers_aprs){
	if (msg['json_data'] != 0){
		var json_packet = msg['json_data'];
        change_data(msg['type'],k);
		var json = JSON.parse(json_packet);
			json.forEach(function (item, i, json) {

				    j = json[i];
				    lat = j.lat;
				    lon = j.lon;
				    $('#id').html(j.id);
				    $('#numberOfFlight').html(j.numberOfFlight);
				    $('#datetime').html(j.datetime);
				    $('#lat').html(j.lat);
				    $('#lon').html(j.lon);
				    $('#alt').html(j.alt);
				    $('#temp1').html(j.temp1);
				    $('#pressure1').html(j.pressure);

				    id_aprs = j.id;
				    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
				    addMarker(position,map,lat,lon,markers_aprs,'aprs');
				    console.log("Данные aпрс есть, омномном");

                    socket.emit('my_event2',{data: id_aprs});
			})
	}  else {
	console.log("Данных апрс нема, хозяина");
	socket.emit('my_event2',{data: id_aprs});}
}
function GPRS(msg,markers_gprs){
					if (msg['json_data'] != 0){
                        change_data(msg['type'],k);

						var json_packet = msg['json_data'];

						var json = JSON.parse(json_packet);
									json.forEach(function (item, i, json) {
									    j = json[i];
									    lat = j.lat;
									    lon = j.lon;
									    $('#id').html(j.id);
									    $('#numberOfFlight').html(j.numberOfFlight);
									    $('#datetime').html(j.datetime);
									    $('#lat').html(j.lat);
									    $('#lon').html(j.lon);
									    $('#alt').html(j.alt);
									    $('#temp1').html(j.temp1);
									    $('#pressure1').html(j.pressure1);
									    $('#pressure2').html(j.pressure2);
									    $('#bat_volt').html(j.bat_volt);
									    $('#vect_axel1x').html(j.vect_axel1x);
									    $('#vect_axel1y').html(j.vect_axel1y);
									    $('#vect_axel1z').html(j.vect_axel1z);

									    $('#hdop').html(j.hdop);
									    $('#vdop').html(j.vdop);
									    $('#sats').html(j.sats);
									    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
										id_gprs = j.id;
									    addMarker(position,map,lat,lon,markers_gprs,'gprs');
									    console.log("Данные гпрс есть, омномном");
                                        socket.emit('my_event',{data: id_gprs});
									})
					}   else {
			console.log("Данных гпрс нема, хозяина");
			socket.emit('my_event',{data: id_gprs}); }

};
function TELEMETRY(msg,markers_telemetry) {
					if (msg['json_data'] != 0){
                        change_data(msg['type'],k);

						var json_packet = msg['json_data'];

						var json = JSON.parse(json_packet);
									json.forEach(function (item, i, json) {
									    j = json[i];
									    lat = j.lat;
									    lon = j.lon;
									    $('#id').html(j.id);
									    $('#numberOfFlight').html(j.numberOfFlight);
									    $('#datetime').html(j.datetime);
									    $('#lat').html(j.lat);
									    $('#lon').html(j.lon);
									    $('#alt').html(j.alt);
									    $('#temp1').html(j.temp1);

									    $('#pressure1').html(j.pressure1);
									    $('#pressure2').html(j.pressure2);
									    $('#bat_volt').html(j.bat_volt);
									    $('#vect_axel1x').html(j.vect_axel1x);
									    $('#vect_axel1y').html(j.vect_axel1y);
									    $('#vect_axel1z').html(j.vect_axel1z);

									    $('#hdop').html(j.hdop);
									    $('#vdop').html(j.vdop);
									    $('#sats').html(j.sats);
									    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
										id_telemetry = j.id;
									    addMarker(position,map,lat,lon,markers_telemetry,'telemetry');
									    console.log("Данные телеметрии есть, омномном");
                                        socket.emit('my_event3',{data: id_telemetry});
									})
					}    else {
			console.log("Данных телеметрии нема, хозяина");
			socket.emit('my_event3',{data: id_telemetry}); 	}

};

});
function changeMarkers(map,mas) {
        for (var i = 0; i < mas.length; i++) {
          mas[i].setMap(map);
        }
}

function addMarker(location, map,lat,lon,massive,type, l){

	if ($("#follow").prop("checked")){map.setCenter(location)};
    if(type == '----'){
		var marker = new google.maps.Marker({position: location,map: map});
	}
	if(type == 'gprs'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon.ico"});
	}
	if(type == 'aprs'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon1.png"});
	}
	if(type == 'telemetry'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon2.png"});
	}
	marker.setMap(map);
	if (!!massive[l]){
		el = massive.shift();
		el.setMap(null)
		massive.push(marker);
		var lastMarker = massive[massive.length - 1];
		lastMarker.setMap(map)

		}
	else{
		massive.push(marker);
		marker.setMap(map)
		};
	marker.setMap(map);

};
<commit_msg>Вроде починил (но это не точно)<commit_after>$(document).ready(function () {
var markers_gprs = [];
var markers_aprs = [];
var markers_telemetry = [];
var markers_Oleg = [];
var id_gprs = 0;
var id_aprs = 0;
var id_telemetry = 0;

var url = 'http://' + document.domain + ':' + location.port;
var socket = io.connect(url + "/mcc");
	socket.on('connect', function() {
		socket.emit('last_dots');
	});
socket.emit('Oleg');

socket.on('lastMarkerOleg', function (msg) {
	setTimeout(function(){
		try{
		    var gprs = msg['Oleg'];
		    var json = JSON.parse(gprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_Oleg,'----',1);
		    })
		} catch(e) {console.log("Не удалось взять данные с трекера");}
            socket.emit('Oleg');
}, 60000);
});

socket.on('lastMarkers', function (msg) {

		var gprs = msg['gprs'];
		try{
		    var json = JSON.parse(gprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_gprs,'gprs',9);
		    })
		}catch(e){console.log("Не удалось взять последние точки gprs");}

		var aprs = msg['aprs'];
		try{

            var json = JSON.parse(aprs);
		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_aprs,'aprs',9);
		    })
		}catch(e){console.log("Не удалось взять последние точки aprs");}

		var telemetry = msg['telemetry'];
		try{

		    var json = JSON.parse(telemetry);

		    json.forEach(function (item, i, json) {
			    j = json[i];
			    lat = j.lat;
			    lon = j.lon;
			    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
			    addMarker(position,map,lat,lon,markers_telemetry,'telemetry',9);
		    })
	}catch(e){console.log("Не удалось взять последние точки телеметрии");}

})
socket.emit('my_event',{data: 0});
k=0;
i =0;
socket.on('gprs', function (msg) {
	if (i==0){
		GPRS(msg,markers_gprs);
		i=1;
		 }
	else	{
			setTimeout(function(){
	  		GPRS(msg,markers_gprs);
			}, 5000);
		}

});

n=0
socket.emit('my_event2',{data: 0});
socket.on('aprs', function (msg) {
	if (n==0){
		APRS(msg,markers_aprs);
		n=1;
	}
	else	{
			setTimeout(function(){
	  		APRS(msg,markers_aprs);
			}, 10000);
		}
});

g=0
socket.emit('my_event3',{data: 0});

socket.on('telemetry', function (msg) {
	if (g==0){
  		TELEMETRY(msg,markers_telemetry);
		g=1;
	}
	else	{
			setTimeout(function(){
	  		TELEMETRY(msg,markers_telemetry);
			}, 10000);
		}
});

$("#telemetry").change(function(){
	if($("#telemetry").prop("checked")){changeMarkers(map,markers_telemetry)}
	else {changeMarkers(null,markers_telemetry)} });
$("#gprs").change(function(){
	if($("#gprs").prop("checked")){changeMarkers(map,markers_gprs)}
	else  {changeMarkers(null,markers_gprs)}});
$("#aprs").change(function(){
	if($("#aprs").prop("checked")) {changeMarkers(map,markers_aprs)}
	else {changeMarkers(null,markers_aprs)} });

function APRS(msg,markers_aprs){
	if (msg['json_data'] != 0){
		var json_packet = msg['json_data'];
        change_data(msg['type'],k);
		var json = JSON.parse(json_packet);
			json.forEach(function (item, i, json) {

				    j = json[i];
				    lat = j.lat;
				    lon = j.lon;
				    $('#id').html(j.id);
				    $('#numberOfFlight').html(j.numberOfFlight);
				    $('#datetime').html(j.datetime);
				    $('#lat').html(j.lat);
				    $('#lon').html(j.lon);
				    $('#alt').html(j.alt);
				    $('#temp1').html(j.temp1);
				    $('#pressure1').html(j.pressure);

				    id_aprs = j.id;
				    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
				    addMarker(position,map,lat,lon,markers_aprs,'aprs');
				    console.log("Данные aпрс есть, омномном");

                    socket.emit('my_event2',{data: id_aprs});
			})
	}  else {
	console.log("Данных апрс нема, хозяина");
	socket.emit('my_event2',{data: id_aprs});}
}
function GPRS(msg,markers_gprs){
					if (msg['json_data'] != 0){
                        change_data(msg['type'],k);

						var json_packet = msg['json_data'];

						var json = JSON.parse(json_packet);
									json.forEach(function (item, i, json) {
									    j = json[i];
									    lat = j.lat;
									    lon = j.lon;
									    $('#id').html(j.id);
									    $('#numberOfFlight').html(j.numberOfFlight);
									    $('#datetime').html(j.datetime);
									    $('#lat').html(j.lat);
									    $('#lon').html(j.lon);
									    $('#alt').html(j.alt);
									    $('#temp1').html(j.temp1);
									    $('#pressure1').html(j.pressure1);
									    $('#pressure2').html(j.pressure2);
									    $('#bat_volt').html(j.bat_volt);
									    $('#vect_axel1x').html(j.vect_axel1x);
									    $('#vect_axel1y').html(j.vect_axel1y);
									    $('#vect_axel1z').html(j.vect_axel1z);

									    $('#hdop').html(j.hdop);
									    $('#vdop').html(j.vdop);
									    $('#sats').html(j.sats);
									    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
										id_gprs = j.id;
									    addMarker(position,map,lat,lon,markers_gprs,'gprs');
									    console.log("Данные гпрс есть, омномном");
                                        socket.emit('my_event',{data: id_gprs});
									})
					}   else {
			console.log("Данных гпрс нема, хозяина");
			socket.emit('my_event',{data: id_gprs}); }

};
function TELEMETRY(msg,markers_telemetry) {
					if (msg['json_data'] != 0){
                        change_data(msg['type'],k);

						var json_packet = msg['json_data'];

						var json = JSON.parse(json_packet);
									json.forEach(function (item, i, json) {
									    j = json[i];
									    lat = j.lat;
									    lon = j.lon;
									    $('#id').html(j.id);
									    $('#numberOfFlight').html(j.numberOfFlight);
									    $('#datetime').html(j.datetime);
									    $('#lat').html(j.lat);
									    $('#lon').html(j.lon);
									    $('#alt').html(j.alt);
									    $('#temp1').html(j.temp1);

									    $('#pressure1').html(j.pressure1);
									    $('#pressure2').html(j.pressure2);
									    $('#bat_volt').html(j.bat_volt);
									    $('#vect_axel1x').html(j.vect_axel1x);
									    $('#vect_axel1y').html(j.vect_axel1y);
									    $('#vect_axel1z').html(j.vect_axel1z);

									    $('#hdop').html(j.hdop);
									    $('#vdop').html(j.vdop);
									    $('#sats').html(j.sats);
									    var position = {lat: parseFloat(lat), lng: parseFloat(lon)};
										id_telemetry = j.id;
									    addMarker(position,map,lat,lon,markers_telemetry,'telemetry');
									    console.log("Данные телеметрии есть, омномном");
                                        socket.emit('my_event3',{data: id_telemetry});
									})
					}    else {
			console.log("Данных телеметрии нема, хозяина");
			socket.emit('my_event3',{data: id_telemetry}); 	}

};

});
function changeMarkers(map,mas) {
        for (var i = 0; i < mas.length; i++) {
          mas[i].setMap(map);
        }
}

function addMarker(location, map,lat,lon,massive,type, l){

	if ($("#follow").prop("checked")){map.setCenter(location)};
    if(type == '----'){
		var marker = new google.maps.Marker({position: location,map: map});
	}
	if(type == 'gprs'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon.ico"});
	}
	if(type == 'aprs'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon1.png"});
	}
	if(type == 'telemetry'){
		var marker = new google.maps.Marker({position: location,map: map,icon: "../static/img/icon2.png"});
	}
	marker.setMap(map);
	if (!!massive[l]){
		el = massive.shift();
		el.setMap(null)
		massive.push(marker);
		var lastMarker = massive[massive.length - 1];
		lastMarker.setMap(map)

		}
	else{
		massive.push(marker);
		marker.setMap(map)
		};
	marker.setMap(map);

};
<|endoftext|>


<commit_before>import React from 'react'
import Polyline from './polyline'

export default class Svg extends React.Component {
  constructor() {
    super()
    this.state = {
      scale: 1,
      translate: 0
    }
    this.handleZoomIn = this.handleZoomIn.bind(this)
    this.handleZoomOut = this.handleZoomOut.bind(this)
    this.handleResetZoom = this.handleResetZoom.bind(this)
  }

  handleZoomIn() {
    this.setState({
      scale: this.state.scale * 1.2,
      translate: this.state.translate - 40
    })
  }

  handleZoomOut() {
    this.setState({
      scale: this.state.scale / 1.2,
      translate: this.state.translate + 40
    })
  }

  handleResetZoom() {
    this.setState({
      scale: 1, translate: 0
    })
  }

  renderPolylines(surveys) {
    return surveys.map((survey) => {
        const points = survey.svg_polyline_points || []
        return(
          <Polyline points={points} key={survey.key} survey={survey}/>
        )
      }
    )
  }

  render() {
    const cave = this.props.cave
    const surveys = cave.surveys || []
    console.log(this.state.translate)
    return (

          <button className="btn btn-default" onClick={this.handleZoomIn}>

          </button>
          <button className="btn btn-default" onClick={this.handleZoomOut}>

          </button>
          <button className="btn btn-default" onClick={this.handleResetZoom}>
            Reset
          </button>

          <svg key={cave.id} width="100%" viewBox="0 0 500 500">
            <g
              transform={`
                translate(${this.state.translate} ${this.state.translate})
                scale(${this.state.scale})
              `}>
              {this.renderPolylines(surveys)}
            </g>
          </svg>

    )
  }
}
<commit_msg>Ripping out the custom zoom<commit_after>import React from 'react'
import Polyline from './polyline'

export default class Svg extends React.Component {

  renderPolylines(surveys) {
    return surveys.map((survey) => {
        const points = survey.svg_polyline_points || []
        return(
          <Polyline points={points} key={survey.key} survey={survey}/>
        )
      }
    )
  }

  render() {
    const cave = this.props.cave
    const surveys = cave.surveys || []
    return (

        <svg key={cave.id} width="100%" viewBox="0 0 500 500">
          {this.renderPolylines(surveys)}
        </svg>

    )
  }
}
<|endoftext|>