text:
package com.intellij.util.containers;

import com.intellij.concurrency.ConcurrentCollectionFactory;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ref.GCUtil;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import static org.junit.Assert.*;

// tests various ContainerUtil.create* and ContainerUtil.new* collections for being really weak/soft/concurrent
public class ContainerUtilCollectionsTest {
  private static final long TIMEOUT = 5 * 60 * 1000;  // 5 minutes

  private static final TObjectHashingStrategy<String> IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY = new TObjectHashingStrategy<String>() {
    @Override
    public int computeHashCode(String object) {
      return Character.toLowerCase(object.charAt(object.length() - 1));
    }

    @Override
    public boolean equals(String o1, String o2) {
      return StringUtil.equalsIgnoreCase(o1, o2);
    }
  };

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakMapTossedEvenWithIdentityStrategy() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakMap(ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentSoftMapTossedEvenWithIdentityStrategy() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentSoftMap(10, 0.5f, 8, ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
  }

  private void checkKeyTossedEventually(Map<Object, Object> map) {
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(new Object(), new Object()));
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(new Object(), this));
  }
  private void checkKeyTossedEventually(ObjectIntMap<Object> map) {
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(new Object(), 0));
  }
  private void checkValueTossedEventually(IntObjectMap<Object> map) {
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(0, new Object()));
  }
  private void checkValueTossedEventually(Map<Object, Object> map) {
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(new Object(), new Object()));
    checkClearsEventuallyAfterGCPressure(map, ()->map.put(this, new Object()));
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakKeyWeakValueTossedEvenWithIdentityStrategy() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakKeyWeakValueMap(ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentSoftKeySoftValueTossedEvenWithIdentityStrategy() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentSoftKeySoftValueMap(10, 0.5f, 8, ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakKeySoftValueTossedEvenWithIdentityStrategy() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakKeySoftValueMap(10, 0.5f, 8, ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testWeakMapTossedEvenWithIdentityStrategy() {
    Map<Object, Object> map = ContainerUtil.createWeakMap(10,0.5f,ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testSoftMapTossedEvenWithIdentityStrategy() {
    Map<Object, Object> map = ContainerUtil.createSoftMap(ContainerUtil.identityStrategy());
    checkKeyTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testRemoveFromSoftEntrySet() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentSoftMap();
    map.put(this, this);
    Set<Map.Entry<Object, Object>> entries = map.entrySet();
    assertEquals(1, entries.size());
    Map.Entry<Object, Object> entry = entries.iterator().next();
    entries.remove(entry);

    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testRemoveFromWeakEntrySet() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakMap();
    map.put(this, this);
    Set<Map.Entry<Object, Object>> entries = map.entrySet();
    assertEquals(1, entries.size());
    Map.Entry<Object, Object> entry = entries.iterator().next();
    entries.remove(entry);

    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakMapTossed() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakMap();
    checkKeyTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentSoftMapTossed() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentSoftMap();
    checkKeyTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakValueMapTossed() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakValueMap();
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentSoftValueMapTossed() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentSoftValueMap();
    checkValueTossedEventually(map);
  }

  private void checkClearsEventuallyAfterGCPressure(Map<Object, Object> map, @NotNull Runnable putKey) {
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    putKey.run();

    Object strong = new Object();
    //noinspection SizeReplaceableByIsEmpty
    do {
      map.put(strong, strong);  // to run processQueues();
      assertFalse(map.isEmpty());
      map.remove(strong);
      assertNull(map.get(strong));

      GCUtil.tryGcSoftlyReachableObjects();
      System.gc();
    }
    while (map.size() != 0);
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    map.put(this, this);
    assertEquals(1, map.size());
    map.clear();
    assertEquals(0, map.size());
    assertNull(map.get(strong));
  }

  private static final int RANDOM_INT = 987654321;
  private void checkClearsEventuallyAfterGCPressure(ObjectIntMap<Object> map, @NotNull Runnable put) {
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    put.run();
    strong = new Object();
    //noinspection SizeReplaceableByIsEmpty
    do {
      map.put(strong, RANDOM_INT);  // to run processQueues();
      assertFalse(map.isEmpty());
      map.remove(strong);
      assertEquals(0, map.get(strong));

      GCUtil.tryGcSoftlyReachableObjects();
      System.gc();
    }
    while (map.size() != 0);
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    map.put(this, RANDOM_INT);
    assertEquals(1, map.size());
    map.clear();
    assertEquals(0, map.size());
    assertEquals(0, map.get(strong));
  }

  private void checkClearsEventuallyAfterGCPressure(IntObjectMap<Object> map, @NotNull Runnable put) {
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    put.run();

    strong = new Object();
    //noinspection SizeReplaceableByIsEmpty
    do {
      map.put(RANDOM_INT, strong);  // to run processQueues();
      assertFalse(map.isEmpty());
      map.remove(RANDOM_INT);
      assertNull(map.get(RANDOM_INT));

      GCUtil.tryGcSoftlyReachableObjects();
      System.gc();
    }
    while (map.size() != 0);
    assertTrue(map.isEmpty());
    assertEquals(0, map.size());
    map.put(RANDOM_INT, this);
    assertEquals(1, map.size());
    map.clear();
    assertEquals(0, map.size());
    assertNull(map.get(RANDOM_INT));
  }

  @Test(timeout = TIMEOUT)
  public void testSoftMapCustomStrategy() {
    Map<String, String> map = ContainerUtil.createSoftMap(IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    map.put("ab", "ab");
    assertEquals("ab", map.get("AB"));
    String removed = map.remove("aB");
    assertEquals("ab", removed);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testWeakMapCustomStrategy() {
    Map<String, String> map = ContainerUtil.createWeakMap(10, 0.5f, IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    String keyL = "ab";
    String keyU = StringUtil.toUpperCase(keyL);
    String value = "asdfab";
    map.put(keyL, value);
    assertSame(value, map.get(keyU));
    assertSame(value, map.get(keyL));
    String removed = map.remove("aB");
    assertSame(value, removed);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testWeakNativeHashCodeDoesNotGetCalledWhenCustomStrategyIsSpecified() {
    Map<Object, Object> map = ContainerUtil.createWeakMap(10,0.5f,ContainerUtil.identityStrategy());

    checkHashCodeDoesntCalledFor(map);
  }

  @Test(timeout = TIMEOUT)
  public void testSoftNativeHashCodeDoesNotGetCalledWhenCustomStrategyIsSpecified() {
    Map<Object, Object> map = ContainerUtil.createSoftMap(ContainerUtil.identityStrategy());

    checkHashCodeDoesntCalledFor(map);
  }

  private void checkHashCodeDoesntCalledFor(Map<Object, Object> map) {
    Object key = new Object(){
      @Override
      public int hashCode() {
        fail("must not be called");
        return super.hashCode();
      }
    };
    map.put(key, "ab");
    assertSame("ab", map.get(key));
    map.remove(key);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentSoftCustomStrategy() {
    ConcurrentMap<String, String> map = ContainerUtil.createConcurrentSoftMap(10, 0.7f, 16, IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    map.put("ab", "ab");
    assertEquals(1, map.size());
    assertSame("ab",map.get("AB"));
    String removed = map.remove("aB");
    assertEquals("ab", removed);
    assertTrue(map.isEmpty());
  }

  @Test
  public void testConcurrentSoftNullKey() {
    Map<String, String> map = ContainerUtil.createConcurrentSoftMap();

    tryToInsertNullKeys(map);
  }
  @Test
  public void testConcurrentWeakNullKey() {
    Map<String, String> map = ContainerUtil.createConcurrentWeakMap();

    tryToInsertNullKeys(map);
  }

  @Test(expected = IllegalArgumentException.class)
  public void testConcurrentWeakSoftNullKey() {
    Map<String, String> map = ContainerUtil.createConcurrentWeakKeySoftValueMap(1, 1, 1, IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    tryToInsertNullKeys(map);
  }

  @Test(expected = IllegalArgumentException.class)
  public void testConcurrentWeakWeakNullKey() {
    Map<String, String> map = ContainerUtil.createConcurrentWeakKeyWeakValueMap(IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    tryToInsertNullKeys(map);
  }

  private static void tryToInsertNullKeys(Map<String, String> map) {
    map.put(null, "ab");
    assertEquals(1, map.size());
    assertEquals("ab", map.get(null));
    String removed = map.remove(null);
    assertEquals("ab", removed);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakSoftCustomStrategy() {
    ConcurrentMap<String, String> map = ContainerUtil.createConcurrentWeakKeySoftValueMap(1, 1, 1, IGNORE_CASE_WITH_CRAZY_HASH_STRATEGY);

    map.put("ab", "ab");
    assertEquals(1, map.size());
    assertSame("ab", map.get("AB"));
    String removed = map.remove("aB");
    assertEquals("ab", removed);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentLongObjectHashMap() {
    ConcurrentLongObjectMap<Object> map = ContainerUtil.createConcurrentLongObjectMap();
    for (int i = 0; i < 1000; i++) {
      Object prev = map.put(i, i);
      assertNull(prev);
      Object ret = map.get(i);
      assertTrue(ret instanceof Integer);
      assertEquals(i, ret);

      if (i != 0) {
        Object remove = map.remove(i - 1);
        assertTrue(remove instanceof Integer);
        assertEquals(i - 1, remove);
      }
      assertEquals(map.size(), 1);
    }
    map.clear();
    assertEquals(map.size(), 0);
    assertTrue(map.isEmpty());
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentIntObjectHashMap() {
    IntObjectMap<Object> map = ContainerUtil.createConcurrentIntObjectMap();
    for (int i = 0; i < 1000; i++) {
      Object prev = map.put(i, i);
      assertNull(prev);
      Object ret = map.get(i);
      assertTrue(ret instanceof Integer);
      assertEquals(i, ret);

      if (i != 0) {
        Object remove = map.remove(i - 1);
        assertTrue(remove instanceof Integer);
        assertEquals(i - 1, remove);
      }
      assertEquals(map.size(), 1);
    }
    map.clear();
    assertEquals(map.size(), 0);
  }

  @Test(timeout = TIMEOUT)
  public void testConcurrentWeakKeyWeakValueMapTossed() {
    ConcurrentMap<Object, Object> map = ContainerUtil.createConcurrentWeakKeyWeakValueMap();

    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testSoftKeySoftValueMapTossed() {
    Map<Object, Object> map = ContainerUtil.createSoftKeySoftValueMap();
    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @Test(timeout = TIMEOUT)
  public void testWeakKeySoftValueMapTossed() {
    Map<Object, Object> map = ContainerUtil.createWeakKeySoftValueMap();
    checkKeyTossedEventually(map);
    checkValueTossedEventually(map);
  }

  @SuppressWarnings("FieldCanBeLocal")
  private volatile Object strong;

  @Test
  public void testConcurrentWeakValueSize() {
    Map<String, Object> map = ContainerUtil.createConcurrentWeakValueMap();
    strong = new Object();
    map.put("a", strong);
    map.put("b", new Object());

    GCUtil.tryGcSoftlyReachableObjects();
    assertEquals(1, map.size());

    strong = null;
    GCUtil.tryGcSoftlyReachableObjects();
    assertTrue(map.toString(), map.isEmpty());
  }

  @Test
  public void testConcurrentWeakValuePutIfAbsentMustActuallyPutNewValueIfTheOldWasGced() {
    Map<String, Object> map = ContainerUtil.createConcurrentWeakValueMap();
    checkPutIfAbsent(map);
  }
  @Test
  public void testConcurrentSoftValuePutIfAbsentMustActuallyPutNewValueIfTheOldWasGced() {
    Map<String, Object> map = ContainerUtil.createConcurrentSoftValueMap();
    checkPutIfAbsent(map);
  }
  @Test
  public void testConcurrentIntKeyWeakValuePutIfAbsentMustActuallyPutNewValueIfTheOldWasGced() {
    ConcurrentIntObjectMap<Object> map = ContainerUtil.createConcurrentIntObjectWeakValueMap();
    checkPutIfAbsent(map);
  }
  @Test
  public void testConcurrentIntKeySoftValuePutIfAbsentMustActuallyPutNewValueIfTheOldWasGced() {
    ConcurrentIntObjectMap<Object> map = ContainerUtil.createConcurrentIntObjectSoftValueMap();
    checkPutIfAbsent(map);
  }

  private static void checkPutIfAbsent(Map<String, Object> map) {
    String key = "a";
    map.put(key, new Object());
    String newVal = "xxx";
    int i;
    int N = 1_000_000;
    for (i = 0; i < N; i++) {
      Object prev = map.putIfAbsent(key, newVal);
      if (prev == null) {
        assertSame(newVal, map.get(key));
        break;
      }
      assertEquals(Object.class, prev.getClass());
      Object actual = map.get(key);
      assertNotNull(actual);
      if (actual == newVal) {
        break; // gced, replaced
      }
      assertEquals(Object.class, actual.getClass()); // still not gced, put failed. repeat
    }
    if (i == N) {
      GCUtil.tryGcSoftlyReachableObjects();
      Object prev = map.putIfAbsent(key, newVal);
      assertNull(prev);
      assertSame(newVal, map.get(key));
    }
  }
  private static void checkPutIfAbsent(ConcurrentIntObjectMap<Object> map) {
    int key = 4;
    map.put(key, new Object());
    String newVal = "xxx";
    int i;
    int N = 1_000_000;
    for (i = 0; i < N; i++) {
      Object prev = map.putIfAbsent(key, newVal);
      if (prev == null) {
        assertSame(newVal, map.get(key));
        break;
      }
      assertEquals(Object.class, prev.getClass());
      Object actual = map.get(key);
      assertNotNull(actual);
      if (actual == newVal) {
        break; // gced, replaced
      }
      assertEquals(Object.class, actual.getClass()); // still not gced, put failed. repeat
    }
    if (i == N) {
      GCUtil.tryGcSoftlyReachableObjects();
      Object prev = map.putIfAbsent(key, newVal);
      assertNull(prev);
      assertSame(newVal, map.get(key));
    }
  }

  @Test
  public void testConcurrentHashMapTreeBinifiesItself() {
    class AwfulHashCode {
      @Override
      public int hashCode() {
        return 0;
      }
    }

    ConcurrentMap<Object, Object> map = ConcurrentCollectionFactory.createMap(new TObjectHashingStrategy<Object>() {
      @Override
      public int computeHashCode(Object object) {
        return 0;
      }

      @Override
      public boolean equals(Object o1, Object o2) {
        return o1==o2;
      }
    });
    int N = 1000;
    for (int i = 0; i < N; i++) {
      map.put(new AwfulHashCode(), 0);
    }
    assertEquals(N, map.size());
  }

  @Test
  public void weakSetTossed() {
    Set<Object> set = ContainerUtil.createWeakSet();
    checkClearsEventuallyAfterGCPressure(set);
  }

  private void checkClearsEventuallyAfterGCPressure(Set<Object> set) {
    assertTrue(set.isEmpty());
    set.add(new Object());

    //noinspection SizeReplaceableByIsEmpty
    do {
      set.add(this);  // to run processQueues();
      assertFalse(set.isEmpty());
      set.remove(this);

      GCUtil.tryGcSoftlyReachableObjects();
      System.gc();
    }
    while (set.size() != 0);
    assertTrue(set.isEmpty());
    assertEquals(0, set.size());
    set.add(this);
    assertEquals(1, set.size());
  }

  @Test(timeout = TIMEOUT)
  public void testWeakKeyIntValueMapTossed() {
    ObjectIntMap<Object> map = ContainerUtil.createWeakKeyIntValueMap();
    checkKeyTossedEventually(map);
  }
  @Test(timeout = TIMEOUT)
  public void testIntKeyWeakValueMapTossed() {
    IntObjectMap<Object> map = ContainerUtil.createIntKeyWeakValueMap();
    checkValueTossedEventually(map);
  }
}


text:
'use strict';

const colors = require('ansi-colors');
const gulp = require('gulp');
const log = require('fancy-log');
const path = require('path');
const srcGlobs = require('../test-configs/config').presubmitGlobs;
const through2 = require('through2');

const dedicatedCopyrightNoteSources = /(\.js|\.css|\.go)$/;

const requiresReviewPrivacy =
  'Usage of this API requires dedicated review due to ' +
  'being privacy sensitive. Please file an issue asking for permission' +
  ' to use if you have not yet done so.';

const privateServiceFactory =
  'This service should only be installed in ' +
  'the allowlisted files. Other modules should use a public function ' +
  'typically called serviceNameFor.';

const shouldNeverBeUsed =
  'Usage of this API is not allowed - only for internal purposes.';

const backwardCompat =
  'This method must not be called. It is only retained ' +
  'for backward compatibility during rollout.';

const realiasGetMode =
  'Do not re-alias getMode or its return so it can be ' +
  'DCE\'d. Use explicitly like "getMode().localDev" instead.';

// Terms that must not appear in our source files.
const forbiddenTerms = {
  'DO NOT SUBMIT': '',
  'whitelist|white-list': {
    message: 'Please use the term allowlist instead',
  },
  'blacklist|black-list': {
    message: 'Please use the term denylist instead',
  },
  'grandfather|grandfathered': {
    message: 'Please use the term legacy instead',
  },
  // TODO(dvoytenko, #8464): cleanup allowlist.
  '(^-amp-|\\W-amp-)': {
    message: 'Switch to new internal class form',
    allowlist: [
      'build-system/server/amp4test.js',
      'build-system/server/app-index/boilerplate.js',
      'build-system/server/variable-substitution.js',
      'build-system/tasks/extension-generator/index.js',
      'css/ampdoc.css',
      'css/ampshared.css',
      'extensions/amp-pinterest/0.1/amp-pinterest.css',
      'extensions/amp-pinterest/0.1/follow-button.js',
      'extensions/amp-pinterest/0.1/pin-widget.js',
      'extensions/amp-pinterest/0.1/save-button.js',
      'validator/js/engine/validator_test.js',
    ],
  },
  '(^i-amp-|\\Wi-amp-)': {
    message: 'Switch to new internal ID form',
    allowlist: [
      'build-system/tasks/create-golden-css/css/main.css',
      'build-system/tasks/extension-generator/index.js',
      'css/ampdoc.css',
      'css/ampshared.css',
    ],
  },
  'describe\\.only': '',
  'describes.*\\.only': '',
  'dev\\(\\)\\.assert\\(': 'Use the devAssert function instead.',
  '[^.]user\\(\\)\\.assert\\(': 'Use the userAssert function instead.',
  'it\\.only': '',
  'Math.random[^;()]*=': 'Use Sinon to stub!!!',
  'gulp-util': {
    message:
      '`gulp-util` will be deprecated soon. See ' +
      'https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5 ' +
      'for a list of alternatives.',
  },
  'sinon\\.(spy|stub|mock)\\(': {
    message: 'Use a sandbox instead to avoid repeated `#restore` calls',
  },
  '(\\w*([sS]py|[sS]tub|[mM]ock|clock).restore)': {
    message: 'Use a sandbox instead to avoid repeated `#restore` calls',
  },
  'sinon\\.useFake\\w+': {
    message: 'Use a sandbox instead to avoid repeated `#restore` calls',
  },
  'sandbox\\.(spy|stub|mock)\\([^,\\s]*[iI]?frame[^,\\s]*,': {
    message:
      'Do NOT stub on a cross domain iframe! #5359\n' +
      '  If this is same domain, mark /*OK*/.\n' +
      '  If this is cross domain, overwrite the method directly.',
  },
  'console\\.\\w+\\(': {
    message:
      'If you run against this, use console/*OK*/.[log|error] to ' +
      'allowlist a legit case.',
    allowlist: [
      'build-system/common/check-package-manager.js',
      'build-system/pr-check/build.js',
      'build-system/pr-check/build-targets.js',
      'build-system/pr-check/checks.js',
      'build-system/pr-check/cross-browser-tests.js',
      'build-system/pr-check/dist-bundle-size.js',
      'build-system/pr-check/dist-tests.js',
      'build-system/pr-check/module-dist-bundle-size.js',
      'build-system/pr-check/esm-tests.js',
      'build-system/pr-check/experiment-tests.js',
      'build-system/pr-check/e2e-tests.js',
      'build-system/pr-check/local-tests.js',
      'build-system/pr-check/npm-checks.js',
      'build-system/pr-check/performance-tests.js',
      'build-system/pr-check/utils.js',
      'build-system/pr-check/validator-tests.js',
      'build-system/pr-check/visual-diff-tests.js',
      'build-system/server/app.js',
      'build-system/server/amp4test.js',
      'build-system/tasks/build.js',
      'build-system/tasks/check-exact-versions.js',
      'build-system/tasks/check-owners.js',
      'build-system/tasks/check-types.js',
      'build-system/tasks/dist.js',
      'build-system/tasks/dns-monitor.js',
      'build-system/tasks/helpers.js',
      'build-system/tasks/prettify.js',
      'build-system/tasks/server-tests.js',
      'src/purifier/noop.js',
      'validator/js/engine/parse-css.js',
      'validator/js/engine/validator-in-browser.js',
      'validator/js/engine/validator.js',
      'validator/js/nodejs/index.js', // NodeJs only.
    ],
    checkInTestFolder: true,
  },
  '\\bgetModeObject\\(': {
    message: realiasGetMode,
    allowlist: [
      'src/mode-object.js',
      'src/iframe-attributes.js',
      'dist.3p/current/integration.js',
    ],
  },
  '(?:var|let|const) +IS_DEV +=': {
    message:
      'IS_DEV local var only allowed in mode.js and ' +
      'dist.3p/current/integration.js',
    allowlist: ['src/mode.js', 'dist.3p/current/integration.js'],
  },
  '\\.prefetch\\(': {
    message: 'Do not use preconnect.prefetch, use preconnect.preload instead.',
  },
  'iframePing': {
    message:
      'This is only available in vendor config for temporary workarounds.',
    allowlist: [
      'build-system/server/routes/analytics.js',
      'extensions/amp-analytics/0.1/config.js',
      'extensions/amp-analytics/0.1/requests.js',
    ],
  },
  // Service factories that should only be installed once.
  'installActionServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/inabox/inabox-services.js',
      'src/service/action-impl.js',
      'src/service/core-services.js',
      'src/service/standard-actions-impl.js',
    ],
  },
  'installActionHandler': {
    message: privateServiceFactory,
    allowlist: [
      'src/service/action-impl.js',
      'extensions/amp-access/0.1/amp-access.js',
      'extensions/amp-form/0.1/amp-form.js',
    ],
  },
  'installActivityService': {
    message: privateServiceFactory,
    allowlist: [
      'extensions/amp-analytics/0.1/activity-impl.js',
      'extensions/amp-analytics/0.1/amp-analytics.js',
    ],
  },
  'cidServiceForDocForTesting': {
    message: privateServiceFactory,
    allowlist: ['src/service/cid-impl.js'],
  },
  'installCryptoService': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/crypto-impl.js',
    ],
  },
  'installDocService': {
    message: privateServiceFactory,
    allowlist: [
      'src/amp.js',
      'src/amp-shadow.js',
      'src/inabox/amp-inabox.js',
      'src/service/ampdoc-impl.js',
      'testing/describes.js',
      'testing/iframe.js',
    ],
  },
  'installMutatorServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/inabox/inabox-services.js',
      'src/service/core-services.js',
      'src/service/mutator-impl.js',
    ],
  },
  'installPerformanceService': {
    message: privateServiceFactory,
    allowlist: [
      'src/amp.js',
      'src/amp-shadow.js',
      'src/inabox/amp-inabox.js',
      'src/service/performance-impl.js',
    ],
  },
  'installResourcesServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/inabox/inabox-services.js',
      'src/service/core-services.js',
      'src/service/resources-impl.js',
    ],
  },
  'installStorageServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/storage-impl.js',
    ],
  },
  'installTemplatesService': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/template-impl.js',
    ],
  },
  'installUrlReplacementsServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/inabox/inabox-services.js',
      'src/service/core-services.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  'installViewerServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/inabox/inabox-services.js',
      'src/service/core-services.js',
      'src/service/viewer-impl.js',
    ],
  },
  'installViewportServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/viewport/viewport-impl.js',
    ],
  },
  'installVsyncService': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/resources-impl.js',
      'src/service/viewport/viewport-impl.js',
      'src/service/vsync-impl.js',
    ],
  },
  'installXhrService': {
    message: privateServiceFactory,
    allowlist: [
      'src/runtime.js',
      'src/service/core-services.js',
      'src/service/xhr-impl.js',
    ],
  },
  'installPositionObserverServiceForDoc': {
    message: privateServiceFactory,
    allowlist: [
      // Please keep list alphabetically sorted.
      'extensions/amp-fx-collection/0.1/providers/fx-provider.js',
      'extensions/amp-list/0.1/amp-list.js',
      'extensions/amp-next-page/0.1/next-page-service.js',
      'extensions/amp-next-page/1.0/visibility-observer.js',
      'extensions/amp-position-observer/0.1/amp-position-observer.js',
      'extensions/amp-video-docking/0.1/amp-video-docking.js',
      'src/service/position-observer/position-observer-impl.js',
      'src/service/video-manager-impl.js',
      'src/service/video/autoplay.js',
    ],
  },
  'getServiceForDoc': {
    message:
      'Synchronous access to element services is unreliable (#22414). ' +
      'Use getServicePromiseForDoc() instead.',
    allowlist: [
      // Do not allowlist additional "extensions/*" paths.
      // TODO(#22414): Remove paths as they are migrated off of sync API.
      'extensions/amp-analytics/0.1/instrumentation.js',
      'extensions/amp-analytics/0.1/variables.js',
      'extensions/amp-fx-collection/0.1/providers/fx-provider.js',
      'extensions/amp-gwd-animation/0.1/amp-gwd-animation.js',
      'src/chunk.js',
      'src/element-service.js',
      'src/service.js',
      'src/service/cid-impl.js',
      'src/service/origin-experiments-impl.js',
      'src/services.js',
      'testing/test-helper.js',
    ],
  },
  'initLogConstructor|setReportError': {
    message: 'Should only be called from JS binary entry files.',
    allowlist: [
      '3p/integration.js',
      '3p/ampcontext-lib.js',
      '3p/iframe-transport-client-lib.js',
      '3p/recaptcha.js',
      'ads/alp/install-alp.js',
      'ads/inabox/inabox-host.js',
      'dist.3p/current/integration.js',
      'extensions/amp-access/0.1/amp-login-done.js',
      'extensions/amp-viewer-integration/0.1/examples/amp-viewer-host.js',
      'src/amp-story-player/amp-story-component-manager.js',
      'src/runtime.js',
      'src/log.js',
      'src/web-worker/web-worker.js',
      'tools/experiments/experiments.js',
    ],
  },
  'parseUrlWithA': {
    message: 'Use parseUrl instead.',
    allowlist: [
      'src/url.js',
      'src/service/navigation.js',
      'src/service/url-impl.js',
      'dist.3p/current/integration.js',
      'src/amp-story-player/amp-story-player-impl.js',
    ],
  },
  '\\.sendMessage\\(': {
    message: 'Usages must be reviewed.',
    allowlist: [
      // viewer-impl.sendMessage
      'src/error.js',
      'src/service/navigation.js',
      'src/service/viewer-impl.js',
      'src/service/viewport/viewport-impl.js',
      'src/service/performance-impl.js',
      'src/service/resources-impl.js',
      'extensions/amp-bind/0.1/bind-impl.js',
      'extensions/amp-app-banner/0.1/amp-app-banner.js',
      'extensions/amp-subscriptions/0.1/viewer-subscription-platform.js',
      'extensions/amp-viewer-integration/0.1/highlight-handler.js',
      'extensions/amp-consent/0.1/consent-ui.js',
      'extensions/amp-story/1.0/amp-story-viewer-messaging-handler.js',

      // iframe-messaging-client.sendMessage
      '3p/iframe-messaging-client.js',
      '3p/ampcontext.js',
      '3p/ampcontext-integration.js',
      '3p/recaptcha.js',
      'dist.3p/current/integration.js', // includes previous
    ],
  },
  '\\.sendMessageAwaitResponse\\(': {
    message: 'Usages must be reviewed.',
    allowlist: [
      'extensions/amp-access/0.1/login-dialog.js',
      'extensions/amp-access/0.1/signin.js',
      'extensions/amp-story-education/0.1/amp-story-education.js',
      'extensions/amp-subscriptions/0.1/viewer-subscription-platform.js',
      'src/impression.js',
      'src/service/cid-impl.js',
      'src/service/history-impl.js',
      'src/service/storage-impl.js',
      'src/ssr-template-helper.js',
      'src/service/viewer-impl.js',
      'src/service/viewer-cid-api.js',
      'src/utils/xhr-utils.js',
    ],
  },
  // Privacy sensitive
  'cidForDoc|cidForDocOrNull': {
    message: requiresReviewPrivacy,
    allowlist: [
      // CID service is not allowed in amp4ads. No usage should there be
      // in extensions listed in the amp4ads spec:
      // https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec
      'src/ad-cid.js',
      'src/services.js',
      'src/service/cid-impl.js',
      'src/service/standard-actions-impl.js',
      'src/service/url-replacements-impl.js',
      'extensions/amp-access/0.1/amp-access.js',
      'extensions/amp-subscriptions/0.1/amp-subscriptions.js',
      'extensions/amp-experiment/0.1/variant.js',
      'extensions/amp-experiment/1.0/variant.js',
      'extensions/amp-user-notification/0.1/amp-user-notification.js',
      'extensions/amp-consent/0.1/consent-config.js',
      'extensions/amp-story-interactive/0.1/amp-story-interactive-abstract.js',
    ],
  },
  'getBaseCid': {
    message: requiresReviewPrivacy,
    allowlist: ['src/service/cid-impl.js', 'src/service/viewer-impl.js'],
  },
  'isTrustedViewer': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-bind/0.1/bind-impl.js',
      'src/error.js',
      'src/utils/xhr-utils.js',
      'src/service/navigation.js',
      'src/service/viewer-impl.js',
      'src/service/viewer-interface.js',
      'src/service/viewer-cid-api.js',
      'src/inabox/inabox-viewer.js',
      'src/service/cid-impl.js',
      'src/impression.js',
      'src/ssr-template-helper.js',
    ],
  },
  'prerenderSafe': {
    message: requiresReviewPrivacy,
    allowlist: [
      'build-system/externs/amp.extern.js',
      'extensions/amp-subscriptions-google/0.1/amp-subscriptions-google.js',
      'src/utils/xhr-utils.js',
    ],
  },
  'eval\\(': {
    message: shouldNeverBeUsed,
    allowlist: ['extension/amp-bind/0.1/test/test-bind-expr.js'],
  },
  'storageForDoc': {
    message:
      requiresReviewPrivacy +
      ' Please refer to spec/amp-localstorage.md for more information on' +
      ' the storage service usage.' +
      ' Once approved, please also update the spec/amp-localstorage.md to' +
      ' include your usage.',
    allowlist: [
      // Storage service is not allowed in amp4ads. No usage should there be
      // in extensions listed in the amp4ads spec:
      // https://amp.dev/documentation/guides-and-tutorials/learn/a4a_spec
      'src/services.js',
      'src/service/cid-impl.js',
      'extensions/amp-ad-network-adsense-impl/0.1/responsive-state.js',
      'extensions/amp-app-banner/0.1/amp-app-banner.js',
      'extensions/amp-consent/0.1/consent-state-manager.js',
      'extensions/amp-user-notification/0.1/amp-user-notification.js',
    ],
  },
  'localStorage': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-access/0.1/amp-access-iframe.js',
      'extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js',
      'extensions/amp-script/0.1/amp-script.js',
      'extensions/amp-story/1.0/history.js',
      'extensions/amp-web-push/0.1/amp-web-push-helper-frame.js',
      'extensions/amp-web-push/0.1/amp-web-push-permission-dialog.js',
      'src/experiments.js',
      'src/service/cid-impl.js',
      'src/service/storage-impl.js',
      'testing/fake-dom.js',
    ],
  },
  'sessionStorage': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-access/0.1/amp-access-iframe.js',
      'extensions/amp-accordion/0.1/amp-accordion.js',
      'extensions/amp-script/0.1/amp-script.js',
      'testing/fake-dom.js',
    ],
  },
  'indexedDB': {
    message: requiresReviewPrivacy,
  },
  'openDatabase': requiresReviewPrivacy,
  'requestFileSystem': requiresReviewPrivacy,
  'webkitRequestFileSystem': requiresReviewPrivacy,
  'getAccessReaderId': {
    message: requiresReviewPrivacy,
    allowlist: [
      'build-system/externs/amp.extern.js',
      'extensions/amp-access/0.1/amp-access.js',
      'extensions/amp-access/0.1/access-vars.js',
      'extensions/amp-access-scroll/0.1/scroll-impl.js',
      'extensions/amp-subscriptions/0.1/amp-subscriptions.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  'getAuthdataField': {
    message: requiresReviewPrivacy,
    allowlist: [
      'build-system/externs/amp.extern.js',
      'extensions/amp-access/0.1/amp-access.js',
      'extensions/amp-access/0.1/access-vars.js',
      'extensions/amp-subscriptions/0.1/amp-subscriptions.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  'debugger': '',
  // Overridden APIs.
  '(doc.*)\\.referrer': {
    message: 'Use Viewer.getReferrerUrl() instead.',
    allowlist: [
      '3p/integration.js',
      'ads/google/a4a/utils.js',
      'dist.3p/current/integration.js',
      'src/inabox/inabox-viewer.js',
      'src/service/viewer-impl.js',
      'src/error.js',
      'src/window-interface.js',
    ],
  },
  'getUnconfirmedReferrerUrl': {
    message: 'Use Viewer.getReferrerUrl() instead.',
    allowlist: [
      'extensions/amp-dynamic-css-classes/0.1/amp-dynamic-css-classes.js',
      'src/3p-frame.js',
      'src/iframe-attributes.js',
      'src/service/viewer-impl.js',
      'src/service/viewer-interface.js',
      'src/inabox/inabox-viewer.js',
    ],
  },
  'internalListenImplementation': {
    message:
      'Use `listen()` in either `event-helper` or `3p-frame-messaging`' +
      ', depending on your use case.',
    allowlist: [
      'src/3p-frame-messaging.js',
      'src/event-helper.js',
      'src/event-helper-listen.js',
      'dist.3p/current/integration.js', // includes previous
    ],
  },
  'setTimeout.*throw': {
    message: 'Use dev.error or user.error instead.',
    allowlist: ['src/log.js'],
  },
  '(dev|user)\\(\\)\\.(fine|info|warn|error)\\((?!\\s*([A-Z0-9-]+|[\'"`][A-Z0-9-]+[\'"`]))[^,)\n]*': {
    message:
      'Logging message require explicitly `TAG`, or an all uppercase' +
      ' string as the first parameter',
    allowlist: [
      'build-system/babel-plugins/babel-plugin-transform-dev-methods/index.js',
    ],
  },
  '\\.schedulePass\\(': {
    message: 'schedulePass is heavy, think twice before using it',
    allowlist: ['src/service/mutator-impl.js', 'src/service/resources-impl.js'],
  },
  '\\.requireLayout\\(': {
    message:
      'requireLayout is restricted b/c it affects non-contained elements',
    allowlist: [
      'extensions/amp-animation/0.1/web-animations.js',
      'extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js',
      'src/service/resources-impl.js',
    ],
  },
  '\\.updateLayoutPriority\\(': {
    message: 'updateLayoutPriority is a restricted API.',
    allowlist: [
      'extensions/amp-a4a/0.1/amp-a4a.js',
      'src/base-element.js',
      'src/service/resources-impl.js',
    ],
  },
  'overrideVisibilityState': {
    message: 'overrideVisibilityState is a restricted API.',
    allowlist: [
      'src/friendly-iframe-embed.js',
      'src/multidoc-manager.js',
      'src/service/ampdoc-impl.js',
      'src/service/viewer-impl.js',
    ],
  },
  '\\.scheduleLayoutOrPreload\\(': {
    message: 'scheduleLayoutOrPreload is a restricted API.',
    allowlist: ['src/service/owners-impl.js', 'src/service/resources-impl.js'],
  },
  '(win|Win)(dow)?(\\(\\))?\\.open\\W': {
    message: 'Use dom.openWindowDialog',
    allowlist: ['src/dom.js'],
  },
  '\\.getWin\\(': {
    message: backwardCompat,
    allowlist: [],
  },
  '/\\*\\* @type \\{\\!Element\\} \\*/': {
    message: 'Use assertElement instead of casting to !Element.',
    allowlist: [
      'src/log.js', // Has actual implementation of assertElement.
      'dist.3p/current/integration.js', // Includes the previous.
      'src/polyfills/custom-elements.js',
      'ads/google/imaVideo.js', // Required until #22277 is fixed.
      '3p/twitter.js', // Runs in a 3p window context, so cannot import log.js.
    ],
  },
  'startupChunk\\(': {
    message: 'startupChunk( should only be used during startup',
    allowlist: [
      'src/amp.js',
      'src/chunk.js',
      'src/inabox/amp-inabox.js',
      'src/runtime.js',
      'src/custom-element.js',
      'src/service/resources-impl.js',
    ],
  },
  'AMP_CONFIG': {
    message:
      'Do not access AMP_CONFIG directly. Use isExperimentOn() ' +
      'and getMode() to access config',
    allowlist: [
      'build-system/externs/amp.extern.js',
      'build-system/server/app.js',
      'build-system/tasks/e2e/index.js',
      'build-system/tasks/firebase.js',
      'build-system/tasks/integration.js',
      'build-system/tasks/prepend-global/index.js',
      'build-system/tasks/prepend-global/test.js',
      'build-system/tasks/release/index.js',
      'build-system/tasks/visual-diff/index.js',
      'build-system/tasks/build.js',
      'build-system/tasks/default-task.js',
      'build-system/tasks/dist.js',
      'build-system/tasks/helpers.js',
      'dist.3p/current/integration.js',
      'src/config.js',
      'src/experiments.js',
      'src/mode.js',
      'src/web-worker/web-worker.js', // Web worker custom error reporter.
      'tools/experiments/experiments.js',
      'build-system/server/amp4test.js',
    ],
  },
  'data:image/svg(?!\\+xml;charset=utf-8,)[^,]*,': {
    message:
      'SVG data images must use charset=utf-8: ' +
      '"data:image/svg+xml;charset=utf-8,..."',
    allowlist: ['src/service/ie-intrinsic-bug.js'],
  },
  'new CustomEvent\\(': {
    message: 'Use createCustomEvent() helper instead.',
    allowlist: ['src/event-helper.js'],
  },
  'new FormData\\(': {
    message:
      'Use createFormDataWrapper() instead and call ' +
      'formDataWrapper.getFormData() to get the native FormData object.',
    allowlist: ['src/form-data-wrapper.js'],
  },
  '\\.defer\\(\\)': {
    message: 'Promise.defer() is deprecated and should not be used.',
  },
  '(dev|user)\\(\\)\\.assert(Element|String|Number)?\\(\\s*([A-Z][A-Z0-9-]*,)': {
    message: 'TAG is not an argument to assert(). Will cause false positives.',
  },
  'eslint no-unused-vars': {
    message: 'Use a line-level "no-unused-vars" rule instead.',
    allowlist: ['extensions/amp-access/0.1/iframe-api/access-controller.js'],
  },
  'this\\.skip\\(\\)': {
    message:
      'Use of `this.skip()` is forbidden in test files. Use ' +
      '`this.skipTest()` from within a `before()` block instead. See #17245.',
    checkInTestFolder: true,
    allowlist: ['test/_init_tests.js'],
  },
  '[^\\.]makeBodyVisible\\(': {
    message:
      'This is a protected function. If you are calling this to show ' +
      'body after an error please use `makeBodyVisibleRecovery`',
    allowlist: [
      'src/amp.js',
      'src/amp-shadow.js',
      'src/style-installer.js',
      'src/inabox/amp-inabox.js',
    ],
  },
  'isBuildRenderBlocking': {
    message:
      'This is a protected API. Please only override it the element is ' +
      'render blocking',
    allowlist: [
      'src/service/resources-impl.js',
      'src/service/resource.js',
      'src/custom-element.js',
      'src/base-element.js',
      'extensions/amp-experiment/0.1/amp-experiment.js',
      'extensions/amp-experiment/1.0/amp-experiment.js',
    ],
  },
  '^describe[\\.|\\(|$]': {
    message:
      'Top-level "describe" blocks in test files have been deprecated. ' +
      'Use "describes.{realWin|sandboxed|fakeWin|integration}".',
    allowlist: [
      // Non test files. These can remain.
      'build-system/server/app-index/test/test-amphtml-helpers.js',
      'build-system/server/app-index/test/test-file-list.js',
      'build-system/server/app-index/test/test-html.js',
      'build-system/server/app-index/test/test-self.js',
      'build-system/server/app-index/test/test-template.js',
      'build-system/server/app-index/test/test.js',
      'test/_init_tests.js',
      'test/e2e/test-controller-promise.js',
      'test/e2e/test-expect.js',
      'validator/js/engine/amp4ads-parse-css_test.js',
      'validator/js/engine/htmlparser_test.js',
      'validator/js/engine/keyframes-parse-css_test.js',
      'validator/js/engine/parse-css_test.js',
      'validator/js/engine/parse-srcset_test.js',
      'validator/js/engine/parse-url_test.js',
      'validator/js/engine/validator_test.js',
      'validator/js/gulpjs/test/validate.js',
      // Test files. TODO(#24144): Fix these and remove from the allowlist.
      'ads/google/a4a/shared/test/test-content-recommendation.js',
      'ads/google/a4a/shared/test/test-url-builder.js',
      'ads/google/a4a/test/test-line-delimited-response-handler.js',
      'ads/google/a4a/test/test-traffic-experiments.js',
      'ads/google/a4a/test/test-utils.js',
      'ads/google/test/test-utils.js',
      'extensions/amp-a4a/0.1/test/test-a4a-integration.js',
      'extensions/amp-a4a/0.1/test/test-a4a-var-source.js',
      'extensions/amp-a4a/0.1/test/test-amp-a4a.js',
      'extensions/amp-a4a/0.1/test/test-amp-ad-utils.js',
      'extensions/amp-a4a/0.1/test/test-refresh.js',
      'extensions/amp-access/0.1/test/test-access-expr.js',
      'extensions/amp-access/0.1/test/test-amp-login-done-dialog.js',
      'extensions/amp-access/0.1/test/test-jwt.js',
      'extensions/amp-ad-exit/0.1/test/filters/test-click-delay.js',
      'extensions/amp-ad/0.1/test/test-amp-ad-3p-impl.js',
      'extensions/amp-ad/0.1/test/test-amp-ad-custom.js',
      'extensions/amp-ad/0.1/test/test-amp-ad-xorigin-iframe-handler.js',
      'extensions/amp-addthis/0.1/test/addthis-utils/test-fragment.js',
      'extensions/amp-addthis/0.1/test/addthis-utils/test-rot13.js',
      'extensions/amp-analytics/0.1/test/test-crc32.js',
      'extensions/amp-analytics/0.1/test/test-iframe-transport-client.js',
      'extensions/amp-analytics/0.1/test/test-linker-manager.js',
      'extensions/amp-analytics/0.1/test/test-linker-reader.js',
      'extensions/amp-analytics/0.1/test/test-linker.js',
      'extensions/amp-analytics/0.1/test/test-transport-serializers.js',
      'extensions/amp-analytics/0.1/test/test-vendors.js',
      'extensions/amp-animation/0.1/test/test-css-expr.js',
      'extensions/amp-auto-ads/0.1/test/test-attributes.js',
      'extensions/amp-base-carousel/0.1/test/test-responsive-attributes.js',
      'extensions/amp-bind/0.1/test/test-bind-evaluator.js',
      'extensions/amp-bind/0.1/test/test-bind-expression.js',
      'extensions/amp-bind/0.1/test/test-bind-validator.js',
      'extensions/amp-dynamic-css-classes/0.1/test/test-dynamic-classes.js',
      'extensions/amp-form/0.1/test/test-form-submit-service.js',
      'extensions/amp-fx-collection/0.1/test/integration/test-amp-fx-fly-in.js',
      'extensions/amp-lightbox-gallery/0.1/test/integration/test-amp-lightbox-gallery.js',
      'extensions/amp-list/0.1/test/integration/test-amp-list.js',
      'extensions/amp-live-list/0.1/test/test-poller.js',
      'extensions/amp-next-page/0.1/test/test-config.js',
      'extensions/amp-script/0.1/test/unit/test-amp-script.js',
      'extensions/amp-sidebar/0.1/test/test-toolbar.js',
      'extensions/amp-truncate-text/0.1/test/test-binary-search.js',
      'extensions/amp-viewer-integration/0.1/test/test-findtext.js',
      'test/integration/test-3p-nameframe.js',
      'test/integration/test-actions.js',
      'test/integration/test-amp-ad-3p.js',
      'test/integration/test-amp-ad-fake.js',
      'test/integration/test-amp-analytics.js',
      'test/integration/test-amp-pixel.js',
      'test/integration/test-amp-recaptcha-input.js',
      'test/integration/test-amp-skimlinks.js',
      'test/integration/test-amphtml-ads.js',
      'test/integration/test-boilerplates.js',
      'test/integration/test-configuration.js',
      'test/integration/test-css.js',
      'test/integration/test-extensions-loading.js',
      'test/integration/test-released.js',
      'test/integration/test-toggle-display.js',
      'test/integration/test-video-manager.js',
      'test/integration/test-video-players.js',
      'test/unit/3p/test-3p-messaging.js',
      'test/unit/3p/test-recaptcha.js',
      'test/unit/ads/test-unruly.js',
      'test/unit/test-3p-environment.js',
      'test/unit/test-3p.js',
      'test/unit/test-action.js',
      'test/unit/test-activity.js',
      'test/unit/test-ad-helper.js',
      'test/unit/test-ads-config.js',
      'test/unit/test-alp-handler.js',
      'test/unit/test-amp-context.js',
      'test/unit/test-amp-img.js',
      'test/unit/test-amp-inabox.js',
      'test/unit/test-animation.js',
      'test/unit/test-batched-json.js',
      'test/unit/test-callout-vendors.js',
      'test/unit/test-chunk.js',
      'test/unit/test-cid.js',
      'test/unit/test-css.js',
      'test/unit/test-curve.js',
      'test/unit/test-describes.js',
      'test/unit/test-document-ready.js',
      'test/unit/test-element-service.js',
      'test/unit/test-error.js',
      'test/unit/test-event-helper.js',
      'test/unit/test-experiments.js',
      'test/unit/test-exponential-backoff.js',
      'test/unit/test-finite-state-machine.js',
      'test/unit/test-focus-history.js',
      'test/unit/test-gesture-recognizers.js',
      'test/unit/test-gesture.js',
      'test/unit/test-get-html.js',
      'test/unit/test-ie-media-bug.js',
      'test/unit/test-impression.js',
      'test/unit/test-input.js',
      'test/unit/test-integration.js',
      'test/unit/test-intersection-observer-polyfill.js',
      'test/unit/test-intersection-observer.js',
      'test/unit/test-json.js',
      'test/unit/test-layout-rect.js',
      'test/unit/test-layout.js',
      'test/unit/test-log.js',
      'test/unit/test-mode.js',
      'test/unit/test-motion.js',
      'test/unit/test-mustache.js',
      'test/unit/test-mutator.js',
      'test/unit/test-object.js',
      'test/unit/test-observable.js',
      'test/unit/test-pass.js',
      'test/unit/test-platform.js',
      'test/unit/test-polyfill-document-contains.js',
      'test/unit/test-polyfill-math-sign.js',
      'test/unit/test-polyfill-object-assign.js',
      'test/unit/test-polyfill-object-values.js',
      'test/unit/test-preconnect.js',
      'test/unit/test-pull-to-refresh.js',
      'test/unit/test-purifier.js',
      'test/unit/test-render-delaying-services.js',
      'test/unit/test-resource.js',
      'test/unit/test-resources.js',
      'test/unit/test-sanitizer.js',
      'test/unit/test-service.js',
      'test/unit/test-size-list.js',
      'test/unit/test-srcset.js',
      'test/unit/test-static-template.js',
      'test/unit/test-string.js',
      'test/unit/test-style-installer.js',
      'test/unit/test-style.js',
      'test/unit/test-task-queue.js',
      'test/unit/test-transition.js',
      'test/unit/test-types.js',
      'test/unit/test-url-rewrite.js',
      'test/unit/test-url.js',
      'test/unit/test-viewport.js',
      'test/unit/test-web-components.js',
      'test/unit/utils/test-array.js',
      'test/unit/utils/test-base64.js',
      'test/unit/utils/test-bytes.js',
      'test/unit/utils/test-lru-cache.js',
      'test/unit/utils/test-pem.js',
      'test/unit/utils/test-priority-queue.js',
      'test/unit/utils/test-rate-limit.js',
      'test/unit/web-worker/test-amp-worker.js',
    ],
    checkInTestFolder: true,
  },
};

const bannedTermsHelpString =
  'Please review viewport service for helper ' +
  'methods or mark with `/*OK*/` or `/*REVIEW*/` and consult the AMP team. ' +
  'Most of the forbidden property/method access banned on the ' +
  '`forbiddenTermsSrcInclusive` object can be found in ' +
  '[What forces layout / reflow gist by Paul Irish]' +
  '(https://gist.github.com/paulirish/5d52fb081b3570c81e3a). ' +
  'These properties/methods when read/used require the browser ' +
  'to have the up-to-date value to return which might possibly be an ' +
  'expensive computation and could also be triggered multiple times ' +
  'if we are not careful. Please mark the call with ' +
  '`object./*OK*/property` if you explicitly need to read or update the ' +
  'forbidden property/method or mark it with `object./*REVIEW*/property` ' +
  'if you are unsure and so that it stands out in code reviews.';

const measurementApiDeprecated =
  'getLayoutSize/Box APIs are being deprecated. Please contact the' +
  ' @ampproject/wg-performance for questions.';

const forbiddenTermsSrcInclusive = {
  '\\.innerHTML(?!_)': bannedTermsHelpString,
  '\\.outerHTML(?!_)': bannedTermsHelpString,
  '\\.offsetLeft(?!_)': bannedTermsHelpString,
  '\\.offsetTop(?!_)': bannedTermsHelpString,
  '\\.offsetWidth(?!_)': bannedTermsHelpString,
  '\\.offsetHeight(?!_)': bannedTermsHelpString,
  '\\.offsetParent(?!_)': bannedTermsHelpString,
  '\\.clientLeft(?!_)(?!_)': bannedTermsHelpString,
  '\\.clientTop(?!_)': bannedTermsHelpString,
  '\\.clientWidth(?!_)': bannedTermsHelpString,
  '\\.clientHeight(?!_)': bannedTermsHelpString,
  '\\.scrollWidth(?!_)': 'please use `getScrollWidth()` from viewport',
  '\\.scrollHeight(?!_)': bannedTermsHelpString,
  '\\.scrollTop(?!_)': bannedTermsHelpString,
  '\\.scrollLeft(?!_)': bannedTermsHelpString,
  '\\.computedRole(?!_)': bannedTermsHelpString,
  '\\.computedName(?!_)': bannedTermsHelpString,
  '\\.innerText(?!_)': bannedTermsHelpString,
  '\\.scrollX(?!_)': bannedTermsHelpString,
  '\\.scrollY(?!_)': bannedTermsHelpString,
  '\\.pageXOffset(?!_)': bannedTermsHelpString,
  '\\.pageYOffset(?!_)': bannedTermsHelpString,
  '\\.innerWidth(?!_)': bannedTermsHelpString,
  '\\.innerHeight(?!_)': bannedTermsHelpString,
  '\\.scrollingElement(?!_)': bannedTermsHelpString,
  '\\.computeCTM(?!_)': bannedTermsHelpString,
  // Functions
  '\\.applySize\\(': bannedTermsHelpString,
  '\\.attemptChangeHeight\\(0\\)': 'please consider using `attemptCollapse()`',
  '\\.collapse\\(': bannedTermsHelpString,
  '\\.expand\\(': bannedTermsHelpString,
  '\\.focus\\(': bannedTermsHelpString,
  '\\.getBBox\\(': bannedTermsHelpString,
  '\\.getBoundingClientRect\\(': bannedTermsHelpString,
  '\\.getClientRects\\(': bannedTermsHelpString,
  '\\.getMatchedCSSRules\\(': bannedTermsHelpString,
  '\\.scrollBy\\(': bannedTermsHelpString,
  '\\.scrollIntoView\\(': bannedTermsHelpString,
  '\\.scrollIntoViewIfNeeded\\(': bannedTermsHelpString,
  '\\.scrollTo\\(': bannedTermsHelpString,
  '\\.webkitConvertPointFromNodeToPage\\(': bannedTermsHelpString,
  '\\.webkitConvertPointFromPageToNode\\(': bannedTermsHelpString,
  '\\.scheduleUnlayout\\(': bannedTermsHelpString,
  '\\.postMessage\\(': {
    message: bannedTermsHelpString,
    allowlist: [
      'extensions/amp-install-serviceworker/0.1/amp-install-serviceworker.js',
      'src/service/viewport/viewport-impl.js',
    ],
  },
  'getComputedStyle\\(': {
    message:
      'Due to various bugs in Firefox, you must use the computedStyle ' +
      'helper in style.js.',
    allowlist: [
      'src/style.js',
      'dist.3p/current/integration.js',
      'build-system/tasks/coverage-map/index.js',
    ],
  },
  'decodeURIComponent\\(': {
    message:
      'decodeURIComponent throws for malformed URL components. Please ' +
      'use tryDecodeUriComponent from src/url.js',
    allowlist: [
      '3p/integration.js',
      'dist.3p/current/integration.js',
      'examples/pwa/pwa.js',
      'validator/js/engine/parse-url.js',
      'validator/js/engine/validator.js',
      'validator/js/webui/webui.js',
      'extensions/amp-pinterest/0.1/util.js',
      'src/url.js',
      'src/url-try-decode-uri-component.js',
      'src/utils/bytes.js',
    ],
  },
  'Text(Encoder|Decoder)\\(': {
    message:
      'TextEncoder/TextDecoder is not supported in all browsers.' +
      ' Please use UTF8 utilities from src/bytes.js',
    allowlist: [
      'ads/google/a4a/line-delimited-response-handler.js',
      'examples/pwa/pwa.js',
      'src/utils/bytes.js',
      'src/utils/stream-response.js',
    ],
  },
  'contentHeightChanged': {
    message: bannedTermsHelpString,
    allowlist: [
      'src/inabox/inabox-viewport.js',
      'src/service/resources-impl.js',
      'src/service/viewport/viewport-binding-def.js',
      'src/service/viewport/viewport-binding-ios-embed-wrapper.js',
      'src/service/viewport/viewport-binding-natural.js',
      'src/service/viewport/viewport-impl.js',
      'src/service/viewport/viewport-interface.js',
    ],
  },
  'preloadExtension': {
    message: bannedTermsHelpString,
    allowlist: [
      'src/element-stub.js',
      'src/friendly-iframe-embed.js',
      'src/polyfillstub/intersection-observer-stub.js',
      'src/polyfillstub/resize-observer-stub.js',
      'src/runtime.js',
      'src/service/extensions-impl.js',
      'src/service/lightbox-manager-discovery.js',
      'src/service/crypto-impl.js',
      'src/shadow-embed.js',
      'src/analytics.js',
      'src/extension-analytics.js',
      'src/services.js',
      'extensions/amp-ad/0.1/amp-ad.js',
      'extensions/amp-a4a/0.1/amp-a4a.js',
      'extensions/amp-a4a/0.1/head-validation.js',
      'extensions/amp-a4a/0.1/template-validator.js',
      'extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js',
      'extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js',
      'extensions/amp-lightbox-gallery/0.1/amp-lightbox-gallery.js',
      'extensions/amp-animation/0.1/install-polyfill.js',
    ],
  },
  'loadElementClass': {
    message: bannedTermsHelpString,
    allowlist: [
      'src/runtime.js',
      'src/service/extensions-impl.js',
      'extensions/amp-ad/0.1/amp-ad.js',
      'extensions/amp-a4a/0.1/amp-a4a.js',
      'extensions/amp-auto-ads/0.1/amp-auto-ads.js',
      'extensions/amp-auto-ads/0.1/anchor-ad-strategy.js',
    ],
  },
  'reject\\(\\)': {
    message:
      'Always supply a reason in rejections. ' +
      'error.cancellation() may be applicable.',
  },
  '[^.]loadPromise': {
    message: 'Most users should use BaseElement…loadPromise.',
    allowlist: [
      'src/base-element.js',
      'src/event-helper.js',
      'src/friendly-iframe-embed.js',
      'src/service/performance-impl.js',
      'src/service/resources-impl.js',
      'src/service/url-replacements-impl.js',
      'src/service/variable-source.js',
      'src/validator-integration.js',
      'extensions/amp-ad/0.1/amp-ad-xorigin-iframe-handler.js',
      'extensions/amp-image-lightbox/0.1/amp-image-lightbox.js',
      'extensions/amp-analytics/0.1/transport.js',
      'extensions/amp-web-push/0.1/iframehost.js',
      'extensions/amp-recaptcha-input/0.1/amp-recaptcha-service.js',
      'dist.3p/current/integration.js',
    ],
  },
  '\\.getTime\\(\\)': {
    message: 'Unless you do weird date math (allowlist), use Date.now().',
    allowlist: [
      'extensions/amp-timeago/0.1/amp-timeago.js',
      'extensions/amp-timeago/1.0/timeago.js',
      'src/utils/date.js',
    ],
  },
  '\\.expandStringSync\\(': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-form/0.1/amp-form.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  '\\.expandStringAsync\\(': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-form/0.1/amp-form.js',
      'src/service/url-replacements-impl.js',
      'extensions/amp-analytics/0.1/config.js',
      'extensions/amp-analytics/0.1/cookie-writer.js',
      'extensions/amp-analytics/0.1/requests.js',
      'extensions/amp-analytics/0.1/variables.js',
    ],
  },
  '\\.expandInputValueSync\\(': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-form/0.1/amp-form.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  '\\.expandInputValueAsync\\(': {
    message: requiresReviewPrivacy,
    allowlist: [
      'extensions/amp-form/0.1/amp-form.js',
      'src/service/url-replacements-impl.js',
    ],
  },
  '\\.setNonBoolean\\(': {
    message: requiresReviewPrivacy,
    allowlist: [
      'src/service/cid-impl.js',
      'src/service/storage-impl.js',
      'extensions/amp-consent/0.1/consent-state-manager.js',
    ],
  },
  '(cdn|3p)\\.ampproject\\.': {
    message:
      'The CDN domain should typically not be hardcoded in source ' +
      'code. Use a property of urls from src/config.js instead.',
    allowlist: [
      'ads/_a4a-config.js',
      'build-system/server/amp4test.js',
      'build-system/server/app-index/amphtml-helpers.js',
      'build-system/server/app-utils.js',
      'build-system/server/app-video-testbench.js',
      'build-system/server/app.js',
      'build-system/server/shadow-viewer.js',
      'build-system/server/variable-substitution.js',
      'build-system/tasks/check-links.js',
      'build-system/tasks/dist.js',
      'build-system/tasks/extension-generator/index.js',
      'build-system/tasks/helpers.js',
      'build-system/tasks/performance/helpers.js',
      'dist.3p/current/integration.js',
      'extensions/amp-iframe/0.1/amp-iframe.js',
      'src/3p-frame.js',
      'src/amp-story-player/amp-story-player-impl.js',
      'src/config.js',
      'testing/local-amp-chrome-extension/background.js',
      'tools/errortracker/errortracker.go',
      'tools/experiments/experiments.js',
      'validator/js/engine/htmlparser-interface.js',
      'validator/js/engine/validator-in-browser.js',
      'validator/js/engine/validator.js',
      'validator/js/nodejs/index.js',
      'validator/js/webui/serve-standalone.go',
    ],
  },
  '\\<\\<\\<\\<\\<\\<': {
    message: 'Unresolved merge conflict.',
  },
  '\\>\\>\\>\\>\\>\\>': {
    message: 'Unresolved merge conflict.',
  },
  '\\.indexOf\\([\'"][^)]+\\)\\s*===?\\s*0\\b': {
    message: 'use startsWith helper in src/string.js',
    allowlist: ['dist.3p/current/integration.js', 'build-system/server/app.js'],
  },
  '\\.indexOf\\(.*===?.*\\.length': 'use endsWith helper in src/string.js',
  '/url-parse-query-string': {
    message: 'Import parseQueryString from `src/url.js`',
    allowlist: ['src/url.js', 'src/mode.js', 'dist.3p/current/integration.js'],
  },
  '\\.trim(Left|Right)\\(\\)': {
    message: 'Unsupported on IE; use trim() or a helper instead.',
    allowlist: ['validator/js/engine/validator.js'],
  },
  "process\\.env(\\.|\\[\\')(TRAVIS|GITHUB_ACTIONS|CIRCLECI)": {
    message:
      'Do not directly use CI-specific environment vars. Instead, add a ' +
      'function to build-system/common/ci.js',
  },
  '\\.matches\\(': 'Please use matches() helper in src/dom.js',
  '\\.getLayoutBox': {
    message: measurementApiDeprecated,
    allowlist: [
      'src/base-element.js',
      'src/custom-element.js',
      'src/friendly-iframe-embed.js',
      'src/service/mutator-impl.js',
      'src/service/resource.js',
      'src/service/resources-impl.js',
      'extensions/amp-ad/0.1/amp-ad-3p-impl.js',
      'extensions/amp-ad-network-adsense-impl/0.1/responsive-state.js',
      'extensions/amp-fx-flying-carpet/0.1/amp-fx-flying-carpet.js',
      'extensions/amp-iframe/0.1/amp-iframe.js',
      'extensions/amp-next-page/1.0/visibility-observer.js',
      'extensions/amp-playbuzz/0.1/amp-playbuzz.js',
      'extensions/amp-story/1.0/page-advancement.js',
    ],
  },
  '\\.getIntersectionElementLayoutBox': {
    message: measurementApiDeprecated,
    allowlist: [
      'src/custom-element.js',
      'extensions/amp-a4a/0.1/amp-a4a.js',
      'extensions/amp-ad/0.1/amp-ad-3p-impl.js',
      'extensions/amp-ad-network-adsense-impl/0.1/amp-ad-network-adsense-impl.js',
      'extensions/amp-ad-network-doubleclick-impl/0.1/amp-ad-network-doubleclick-impl.js',
      'extensions/amp-iframe/0.1/amp-iframe.js',
    ],
  },
};

// Terms that must appear in a source file.
const requiredTerms = {
  'Copyright 20(15|16|17|18|19|2\\d) The AMP HTML Authors\\.': dedicatedCopyrightNoteSources,
  'Licensed under the Apache License, Version 2\\.0': dedicatedCopyrightNoteSources,
  'http\\://www\\.apache\\.org/licenses/LICENSE-2\\.0': dedicatedCopyrightNoteSources,
};

/**
 * Check if root of path is test/ or file is in a folder named test.
 * @param {string} path
 * @return {boolean}
 */
function isInTestFolder(path) {
  const dirs = path.split('/');
  return dirs.indexOf('test') >= 0;
}

/**
 * Check if file is inside the build-system/babel-plugins test/fixture folder.
 * @param {string} filePath
 * @return {boolean}
 */
function isInBuildSystemFixtureFolder(filePath) {
  const folder = path.dirname(filePath);
  return (
    folder.startsWith('build-system/babel-plugins') &&
    folder.includes('test/fixtures')
  );
}

/**
 * Strip Comments
 * @param {string} contents
 * @return {string}
 */
function stripComments(contents) {
  // Multi-line comments
  contents = contents.replace(/\/\*(?!.*\*\/)(.|\n)*?\*\//g, function (match) {
    // Preserve the newlines
    const newlines = [];
    for (let i = 0; i < match.length; i++) {
      if (match[i] === '\n') {
        newlines.push('\n');
      }
    }
    return newlines.join('');
  });
  // Single line comments either on its own line or following a space,
  // semi-colon, or closing brace
  return contents.replace(/( |}|;|^) *\/\/.*/g, '$1');
}

/**
 * Logs any issues found in the contents of file based on terms (regex
 * patterns), and provides any possible fix information for matched terms if
 * possible
 *
 * @param {!File} file a vinyl file object to scan for term matches
 * @param {!Array<string, string>} terms Pairs of regex patterns and possible
 *   fix messages.
 * @return {boolean} true if any of the terms match the file content,
 *   false otherwise
 */
function matchTerms(file, terms) {
  const contents = stripComments(file.contents.toString());
  const {relative} = file;
  return Object.keys(terms)
    .map(function (term) {
      let fix;
      const {allowlist, checkInTestFolder} = terms[term];
      // NOTE: we could do a glob test instead of exact check in the future
      // if needed but that might be too permissive.
      if (
        isInBuildSystemFixtureFolder(relative) ||
        (Array.isArray(allowlist) &&
          (allowlist.indexOf(relative) != -1 ||
            (isInTestFolder(relative) && !checkInTestFolder)))
      ) {
        return false;
      }
      // we can't optimize building the `RegExp` objects early unless we build
      // another mapping of term -> regexp object to be able to get back to the
      // original term to get the possible fix value. This is ok as the
      // presubmit doesn't have to be blazing fast and this is most likely
      // negligible.
      const regex = new RegExp(term, 'gm');
      let index = 0;
      let line = 1;
      let column = 0;
      let match;
      let hasTerm = false;

      while ((match = regex.exec(contents))) {
        hasTerm = true;
        for (index; index < match.index; index++) {
          if (contents[index] === '\n') {
            line++;
            column = 1;
          } else {
            column++;
          }
        }

        log(
          colors.red(
            'Found forbidden: "' +
              match[0] +
              '" in ' +
              relative +
              ':' +
              line +
              ':' +
              column
          )
        );
        if (typeof terms[term] === 'string') {
          fix = terms[term];
        } else {
          fix = terms[term].message;
        }

        // log the possible fix information if provided for the term.
        if (fix) {
          log(colors.blue(fix));
        }
        log(colors.blue('=========='));
      }

      return hasTerm;
    })
    .some(function (hasAnyTerm) {
      return hasAnyTerm;
    });
}

/**
 * Test if a file's contents match any of the
 * forbidden terms
 *
 * @param {!File} file file is a vinyl file object
 * @return {boolean} true if any of the terms match the file content,
 *   false otherwise
 */
function hasAnyTerms(file) {
  const pathname = file.path;
  const basename = path.basename(pathname);
  let hasTerms = false;
  let hasSrcInclusiveTerms = false;

  hasTerms = matchTerms(file, forbiddenTerms);

  const isTestFile =
    /^test-/.test(basename) ||
    /^_init_tests/.test(basename) ||
    /_test\.js$/.test(basename) ||
    /storybook\/[^/]+\.js$/.test(pathname);
  if (!isTestFile) {
    hasSrcInclusiveTerms = matchTerms(file, forbiddenTermsSrcInclusive);
  }

  return hasTerms || hasSrcInclusiveTerms;
}

/**
 * Test if a file's contents fail to match any of the required terms and log
 * any missing terms
 *
 * @param {!File} file file is a vinyl file object
 * @return {boolean} true if any of the terms are not matched in the file
 *  content, false otherwise
 */
function isMissingTerms(file) {
  const contents = file.contents.toString();
  return Object.keys(requiredTerms)
    .map(function (term) {
      const filter = requiredTerms[term];
      if (!filter.test(file.path)) {
        return false;
      }

      const matches = contents.match(new RegExp(term));
      if (!matches) {
        log(
          colors.red(
            'Did not find required: "' + term + '" in ' + file.relative
          )
        );
        log(colors.blue('=========='));
        return true;
      }
      return false;
    })
    .some(function (hasMissingTerm) {
      return hasMissingTerm;
    });
}

/**
 * Check a file for all the required terms and
 * any forbidden terms and log any errors found.
 * @return {!Promise}
 */
function presubmit() {
  let forbiddenFound = false;
  let missingRequirements = false;
  return gulp
    .src(srcGlobs)
    .pipe(
      through2.obj(function (file, enc, cb) {
        forbiddenFound = hasAnyTerms(file) || forbiddenFound;
        missingRequirements = isMissingTerms(file) || missingRequirements;
        cb();
      })
    )
    .on('end', function () {
      if (forbiddenFound) {
        log(
          colors.blue(
            'Please remove these usages or consult with the AMP team.'
          )
        );
      }
      if (missingRequirements) {
        log(
          colors.blue(
            'Adding these terms (e.g. by adding a required LICENSE ' +
              'to the file)'
          )
        );
      }
      if (forbiddenFound || missingRequirements) {
        process.exitCode = 1;
      }
    });
}

module.exports = {
  presubmit,
};

presubmit.description =
  'Run validation against files to check for forbidden and required terms';

redpajama_set_name: RedPajamaGithub


text:
require 'test/unit'

class TestPedantic < Test::Unit::TestCase
  Lib = File.expand_path("../../lib/language_sniffer", __FILE__)

  def file(name)
    File.read(File.join(Lib, name))
  end

  def test_language_names_are_sorted
    languages = []
    file("languages.yml").lines.each do |line|
      if line =~ /^(\w+):$/
        languages << $1
      end
    end
    assert_sorted languages
  end

  def test_extensions_are_sorted
    extensions = nil
    file("languages.yml").lines.each do |line|
      if line =~ /^  extensions:$/
        extensions = []
      elsif extensions && line =~ /^  - \.(\w+)$/
        extensions << $1
      else
        assert_sorted extensions if extensions
        extensions = nil
      end
    end
  end

  def test_filenames_are_sorted
    filenames = nil
    file("languages.yml").lines.each do |line|
      if line =~ /^  filenames:$/
        filenames = []
      elsif filenames && line =~ /^  - \.(\w+)$/
        filenames << $1
      else
        assert_sorted filenames if filenames
        filenames = nil
      end
    end
  end

  def assert_sorted(list)
    previous = nil
    list.each do |item|
      if previous && previous > item
        flunk "#{previous} should come after #{item}"
      end
      previous = item
    end
  end
end


text:
using System;
using System.IO;
using Aspose.Words.Drawing;

namespace Aspose.Words
{
    class Program
    {
        static void Main(string[] args)
        {
            // Check for license and apply if exists
            string licenseFile = AppDomain.CurrentDomain.BaseDirectory + "Aspose.Words.lic";
            if (File.Exists(licenseFile))
            {
                // Apply Aspose.Words API License
                Aspose.Words.License license = new Aspose.Words.License();
                // Place license file in Bin/Debug/ Folder
                license.SetLicense("Aspose.Words.lic");
            }

            string filePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + @"\data\" + "Extract Images from Word Document.doc";

            Document wordDocument = new Document(filePath);

            NodeCollection pictures = wordDocument.GetChildNodes(NodeType.Shape, true);
            int imageindex = 0;
            foreach (Shape shape in pictures)
            {
                string imageType = FileFormatUtil.ImageTypeToExtension(shape.ImageData.ImageType);
                if (shape.HasImage)
                {
                    string imageFileName = "Aspose_" + (imageindex++).ToString() + "_" + shape.Name + imageType;
                    shape.ImageData.Save(imageFileName);
                }
            }

        }
    }
}


text:
package brennus;

import brennus.ExpressionBuilder.ExpressionHandler;
import brennus.model.Expression;

/**
 *
 * @author Julien Le Dem
 *
 * @param <T> type of the parent
 */
public final class ExecValueExpressionBuilder<T> extends ValueExpressionBuilder<T, ExecExpressionBuilder<T>, ExecValueExpressionBuilder<T>> {

  ExecValueExpressionBuilder(ExpressionHandler<T> expressionHandler,
      Expression expression) {
    super(new ExecExpressionBuilderFactory<T>(), expressionHandler, expression);
  }

  /**
   * end an exec statement
   * @return parent
   */
  public T endExec() {
    return this.end();
  }

}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace CameraModifications
{
    public class UI_ShowCanvasGroup : MonoBehaviour
    {
        private CanvasGroup group;
        private bool show = false;
        private List<UI_ShowCanvasGroup> childs = new List<UI_ShowCanvasGroup>();
        private bool parentShow = true;
        public bool IsShow
        {
            get
            {
                return this.show;
            }
        }
        private void Awake()
        {
            this.group = base.gameObject.GetComponent<CanvasGroup>();
        }
        private void Start()
        {
            childs = GetComponentsInChildren<UI_ShowCanvasGroup>().Where(group => group != this).ToList();

            this.Show(this.show);
        }
        public void Show(bool flag)
        {
            this.show = flag;
            this.group.alpha = ((!flag) ? 0f : 1f);
            this.group.blocksRaycasts = flag;
            this.group.interactable = flag;

            foreach (var canvasGroup in group.GetComponentsInChildren<CanvasGroup>())
            {
                canvasGroup.alpha = group.alpha;
                canvasGroup.interactable = flag;
                canvasGroup.blocksRaycasts = flag;
            }

            //foreach (UI_ShowCanvasGroup current in this.childs)
            //{
            //    current.Show_FromParent(flag);
            //}
        }
        public void Show_FromParent(bool flag)
        {
            this.parentShow = flag;
            bool flag2 = this.parentShow && this.show;
            this.group.alpha = ((!flag2) ? 0f : 1f);
            this.group.blocksRaycasts = flag2;
            this.group.interactable = flag2;
            foreach (UI_ShowCanvasGroup current in this.childs)
            {
                current.Show_FromParent(flag2);
            }
        }
    }

}


text:
Game Valet is a project to help people who love games.

Game Valet is a web service built to help gamers conquer a library of games without distractions. In this system, users  categorize their video-game collection and receive recommendations for  games they may enjoy. Game Valet provides a simple interface for managing this collection with the help of integrated third-party services.

### Installation & Prerequisites
#### Back-End
Game Valet is built with ``Flask`` on top of ``Python 3.4.3``. No other version of
Python is officially supported. For the back-end, it will suffice to install
the required Python components.

#### Front-End
For the front-end components, Game Valet uses ``Bootstrap`` and custom ``CSS``.
(By nature, Bootstrap requires ``jQuery``.)
These files are included in the repository but can easily be replaced with
a CDN version if preferred.

#### Recommended Installation

Using ``virtualenv`` is useful for Python projects in general but is by no means
required. If you wish to skip the first step below and simply install the
required modules, that will work as well.

```
$ mkvirtualenv gamevalet -p python3
$ pip install -r requirements.txt
```

### Acknowledgements

Thanks to the following projects which made this project possible:

* [``Flask``](http://flask.pocoo.org/)
* [``Flask-user``](https://pythonhosted.org/Flask-User/)
* [``requests``](http://docs.python-requests.org/en/master/)
* [``SQLAlchemy``](http://www.sqlalchemy.org/)
* [GiantBomb and their Developer API](http://www.giantbomb.com/)
* [Steam and their Developer API](http://store.steampowered.com/)

[Flask-User-starter-app](https://github.com/lingthio/Flask-User-starter-app)
was used as a starting point for this code repository.

### COPYRIGHT

This was a project created as a learning experience in an educational environment.
I make no promises with regards to this project.

Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.

IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.


text:
from common.generic_template_tag import GenericTemplateTag
from django.template.loader import render_to_string
from pyalp_page.templatetags.spacer import SpacerNode

class DisplayAllModulesNode(GenericTemplateTag):
    def __init__(self, side=None):
        if side is None:
            raise Exception(
                'Side is required for a display_all_modules template tag'
            )
        else:
            self.side = side

    def render(self, context):
        # displays all the modules for a side.
        side = self.resolve(context, self.side)

        skin = context['skin']
        container = skin.container
        modules = context['modules']

        if side == 'right':
            get_modules = modules.rightModules
            width_modules = container['rightmodule']
        elif side == 'left':
            get_modules = modules.leftModules
            width_modules = container['leftmodule']
        elif side == 'main':
            get_modules = modules.mainModules
            width_modules = '100%'

        if get_modules:
            render_context = {
                'modules': get_modules,
                'width_modules': width_modules
            }

            return render_to_string(
                'display_all_modules.html',
                render_context,
                context_instance=context
            )
        elif side != 'main':
            return SpacerNode(
                skin.container['horizontalpadding']
            ).render({})
        else:
            return ''

from django import template
register = template.Library()
register.tag('display_all_modules', DisplayAllModulesNode.invoke)


text:
layout: post
title: Использование цикла в PostgreSQL с выводом в консоль
tags: [postgresql]
categories: [development]
---

Небольшая заметка на полях на будущее. Иногда в PostgreSQL нужно выполнить ряд повторяющихся действий с выводом результатов в лог.
Одним примером покажу, как это сделать легко и просто.

{% highlight sql %}

-- Делаем вывод сообщений в лог видимым
SET client_min_messages TO notice;

CREATE TEMP TABLE tmp(id SERIAL, name TEXT);

-- Анонимный блок DO
DO $$
BEGIN
    -- Цикл LOOP
    LOOP
        INSERT INTO tmp(name) VALUES(gen_random_uuid()::TEXT);
        -- Условный оператор IF
        IF (SELECT MAX(id) FROM tmp) > 100 THEN
            RAISE NOTICE 'max id == %', (SELECT COUNT(*) FROM tmp);
            EXIT;
        END IF;
    END LOOP;
END $$;

{% endhighlight %}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860

namespace MVC6_Full_Version.Controllers
{
    public class EcommerceController : Controller
    {

        public IActionResult ProductsGrid()
        {
            return View();
        }

        public IActionResult ProductsList()
        {
            return View();
        }

        public IActionResult ProductEdit()
        {
            return View();
        }

        public IActionResult Orders()
        {
            return View();
        }

        public IActionResult ProductDetail()
        {
            return View();
        }

        public IActionResult Payments()
        {
            return View();
        }

        public IActionResult Cart()
        {
            return View();
        }
    }
}


text:
#include <graphene/chain/protocol/authority.hpp>
#include <graphene/app/impacted.hpp>

namespace graphene { namespace app {

using namespace fc;
using namespace graphene::chain;

// TODO:  Review all of these, especially no-ops
struct get_impacted_account_visitor
{
   flat_set<account_id_type>& _impacted;
   get_impacted_account_visitor( flat_set<account_id_type>& impact ):_impacted(impact) {}
   typedef void result_type;

   void operator()( const transfer_operation& op )
   {
      _impacted.insert( op.to );
   }

   void operator()( const asset_claim_fees_operation& op ){}
   void operator()( const limit_order_create_operation& op ) {}
   void operator()( const limit_order_cancel_operation& op )
   {
      _impacted.insert( op.fee_paying_account );
   }
   void operator()( const call_order_update_operation& op ) {}
   void operator()( const fill_order_operation& op )
   {
      _impacted.insert( op.account_id );
   }

   void operator()( const account_create_operation& op )
   {
      _impacted.insert( op.registrar );
      _impacted.insert( op.referrer );
      add_authority_accounts( _impacted, op.owner );
      add_authority_accounts( _impacted, op.active );
   }

   void operator()( const account_update_operation& op )
   {
      _impacted.insert( op.account );
      if( op.owner )
         add_authority_accounts( _impacted, *(op.owner) );
      if( op.active )
         add_authority_accounts( _impacted, *(op.active) );
   }

   void operator()( const account_whitelist_operation& op )
   {
      _impacted.insert( op.account_to_list );
   }

   void operator()( const account_upgrade_operation& op ) {}
   void operator()( const account_transfer_operation& op )
   {
      _impacted.insert( op.new_owner );
   }

   void operator()( const account_balance_migrate_operation& op )
   {
      _impacted.insert( op.account );
   }

   void operator()( const asset_create_operation& op ) {}
   void operator()( const asset_update_operation& op )
   {
      if( op.new_issuer )
         _impacted.insert( *(op.new_issuer) );
   }

   void operator()( const asset_update_bitasset_operation& op ) {}
   void operator()( const asset_update_feed_producers_operation& op ) {}

   void operator()( const asset_issue_operation& op )
   {
      _impacted.insert( op.issue_to_account );
   }

   void operator()( const asset_reserve_operation& op ) {}
   void operator()( const asset_fund_fee_pool_operation& op ) {}
   void operator()( const asset_settle_operation& op ) {}
   void operator()( const asset_global_settle_operation& op ) {}
   void operator()( const asset_publish_feed_operation& op ) {}
   void operator()( const witness_create_operation& op )
   {
      _impacted.insert( op.witness_account );
   }
   void operator()( const witness_update_operation& op )
   {
      _impacted.insert( op.witness_account );
   }

   void operator()( const proposal_create_operation& op )
   {
      vector<authority> other;
      for( const auto& proposed_op : op.proposed_ops )
         operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other );
      for( auto& o : other )
         add_authority_accounts( _impacted, o );
   }

   void operator()( const proposal_update_operation& op ) {}
   void operator()( const proposal_delete_operation& op ) {}

   void operator()( const withdraw_permission_create_operation& op )
   {
      _impacted.insert( op.authorized_account );
   }

   void operator()( const withdraw_permission_update_operation& op )
   {
      _impacted.insert( op.authorized_account );
   }

   void operator()( const withdraw_permission_claim_operation& op )
   {
      _impacted.insert( op.withdraw_from_account );
   }

   void operator()( const withdraw_permission_delete_operation& op )
   {
      _impacted.insert( op.authorized_account );
   }

   void operator()( const committee_member_create_operation& op )
   {
      _impacted.insert( op.committee_member_account );
   }
   void operator()( const committee_member_update_operation& op )
   {
      _impacted.insert( op.committee_member_account );
   }
   void operator()( const committee_member_update_global_parameters_operation& op ) {}

   void operator()( const vesting_balance_create_operation& op )
   {
      _impacted.insert( op.owner );
   }

   void operator()( const vesting_balance_withdraw_operation& op ) {}
   void operator()( const custom_operation& op ) {}
   void operator()( const assert_operation& op ) {}
   void operator()( const balance_claim_operation& op ) {}

   void operator()( const override_transfer_operation& op )
   {
      _impacted.insert( op.to );
      _impacted.insert( op.from );
      _impacted.insert( op.issuer );
   }

   void operator()( const transfer_to_blind_operation& op )
   {
      _impacted.insert( op.from );
      for( const auto& out : op.outputs )
         add_authority_accounts( _impacted, out.owner );
   }

   void operator()( const blind_transfer_operation& op )
   {
      for( const auto& in : op.inputs )
         add_authority_accounts( _impacted, in.owner );
      for( const auto& out : op.outputs )
         add_authority_accounts( _impacted, out.owner );
   }

   void operator()( const transfer_from_blind_operation& op )
   {
      _impacted.insert( op.to );
      for( const auto& in : op.inputs )
         add_authority_accounts( _impacted, in.owner );
   }

   void operator()( const asset_settle_cancel_operation& op )
   {
      _impacted.insert( op.account );
   }

   void operator()( const fba_distribute_operation& op )
   {
      _impacted.insert( op.account_id );
   }

};

void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
{
   get_impacted_account_visitor vtor = get_impacted_account_visitor( result );
   op.visit( vtor );
}

void transaction_get_impacted_accounts( const transaction& tx, flat_set<account_id_type>& result )
{
   for( const auto& op : tx.operations )
      operation_get_impacted_accounts( op, result );
}

} }


text:
/*
 * 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.
 */

package org.jruyi.io.buffer.codec.shortarray;

import static org.jruyi.io.buffer.Helper.B_SIZE_OF_SHORT;
import static org.jruyi.io.buffer.Helper.SIZE_OF_SHORT;

import java.nio.BufferUnderflowException;

import org.jruyi.io.ICodec;
import org.jruyi.io.IUnit;
import org.jruyi.io.IUnitChain;
import org.jruyi.io.buffer.Util;

public abstract class AbstractCodec implements ICodec<short[]> {

	@Override
	public final short[] read(IUnitChain unitChain) {
		IUnit unit = unitChain.currentUnit();
		while (unit.isEmpty()) {
			unit = unitChain.nextUnit();
			if (unit == null)
				throw new BufferUnderflowException();
		}

		int n = unitChain.remaining();
		if (n < 1 || (n & (SIZE_OF_SHORT - 1)) != 0)
			throw new BufferUnderflowException();

		n >>= B_SIZE_OF_SHORT;
		return readShorts(new short[n], 0, n, unitChain);
	}

	@Override
	public final short[] read(IUnitChain unitChain, int length) {
		if (length < 0 || (length & (SIZE_OF_SHORT - 1)) != 0)
			throw new IllegalArgumentException();

		final int n = length >> B_SIZE_OF_SHORT;
		return readShorts(new short[n], 0, n, unitChain);
	}

	@Override
	public final int read(short[] dst, IUnitChain unitChain) {
		final int n = dst.length;
		readShorts(dst, 0, n, unitChain);
		return SIZE_OF_SHORT * n;
	}

	@Override
	public final int read(short[] dst, int offset, int length, IUnitChain unitChain) {
		final int n = offset + length;
		if ((offset | length | n | (dst.length - n)) < 0)
			throw new IndexOutOfBoundsException();

		readShorts(dst, offset, length, unitChain);
		return SIZE_OF_SHORT * length;
	}

	@Override
	public final void write(short[] src, IUnitChain unitChain) {
		writeShorts(src, 0, src.length, unitChain);
	}

	@Override
	public final void write(short[] src, int offset, int length, IUnitChain unitChain) {
		final int n = offset + length;
		if ((offset | length | n | (src.length - n)) < 0)
			throw new IndexOutOfBoundsException();

		writeShorts(src, offset, length, unitChain);
	}

	@Override
	public final short[] get(IUnitChain unitChain, int index) {
		if (index < 0)
			throw new IndexOutOfBoundsException();

		IUnit unit = unitChain.currentUnit();
		int n = unitChain.remaining() + unit.position() - index;
		if (n < 1 || (n & (SIZE_OF_SHORT - 1)) != 0)
			throw new IndexOutOfBoundsException();

		n >>= B_SIZE_OF_SHORT;
		return getShorts(new short[n], 0, n, unitChain, index);
	}

	@Override
	public final short[] get(IUnitChain unitChain, int index, int length) {
		if (index < 0 || length < 0 || (length & (SIZE_OF_SHORT - 1)) != 0)
			throw new IndexOutOfBoundsException();

		final int n = length >> B_SIZE_OF_SHORT;
		return getShorts(new short[n], 0, n, unitChain, index);
	}

	@Override
	public final void get(short[] dst, IUnitChain unitChain, int index) {
		if (index < 0)
			throw new IndexOutOfBoundsException();

		getShorts(dst, 0, dst.length, unitChain, index);
	}

	@Override
	public final void get(short[] dst, int offset, int length, IUnitChain unitChain, int index) {
		final int n = offset + length;
		if ((offset | length | n | (dst.length - n)) < 0 || index < 0)
			throw new IndexOutOfBoundsException();

		getShorts(dst, offset, length, unitChain, index);
	}

	@Override
	public final void set(short[] src, IUnitChain unitChain, int index) {
		if (index < 0)
			throw new IndexOutOfBoundsException();

		setShorts(src, 0, src.length, unitChain, index);
	}

	@Override
	public final void set(short[] src, int offset, int length, IUnitChain unitChain, int index) {
		final int n = offset + length;
		if ((offset | length | n | (src.length - n)) < 0 || index < 0)
			throw new IndexOutOfBoundsException();

		setShorts(src, offset, length, unitChain, index);
	}

	@Override
	public final void prepend(short[] src, IUnitChain unitChain) {
		prependShorts(src, 0, src.length, unitChain);
	}

	@Override
	public final void prepend(short[] src, int offset, int length, IUnitChain unitChain) {
		final int n = offset + length;
		if ((offset | length | n | (src.length - n)) < 0)
			throw new IndexOutOfBoundsException();
		prependShorts(src, offset, length, unitChain);
	}

	abstract boolean isNative();

	abstract IUnit readShort(short[] dst, int offset, IUnit unit, IUnitChain unitChain);

	abstract int getShort(short[] dst, int offset, IUnit unit, int index, IUnitChain unitChain);

	abstract int setShort(short l, IUnit unit, int index, IUnitChain unitChain);

	private short[] readShorts(short[] dst, int offset, int length, IUnitChain unitChain) {
		if (length < 1)
			return dst;

		IUnit unit = unitChain.currentUnit();
		for (;;) {
			int position = unit.position();
			int index = unit.start() + position;
			int m = unit.remaining();
			int k = m >> B_SIZE_OF_SHORT;
			if (k > 0) {
				if (k > length) {
					k = length;
					length = 0;
				} else
					length -= k;
				final int n = k * SIZE_OF_SHORT;
				unit.get(index, n, dst, offset);
				unit.position(position + n);
				if (isNative()) {
					if (length < 1)
						break;
					offset += k;
				} else {
					int i = offset;
					offset += k;
					for (; i < offset; ++i)
						dst[i] = Short.reverseBytes(dst[i]);
					if (length < 1)
						break;
				}
			}
			k = m & (SIZE_OF_SHORT - 1);
			if (k > 0) {
				unit = readShort(dst, offset, unit, unitChain);
				if (--length < 1)
					break;
				++offset;
			} else {
				unit = unitChain.nextUnit();
				if (unit == null)
					throw new BufferUnderflowException();
			}
		}
		return dst;
	}

	private short[] getShorts(short[] dst, int offset, int length, IUnitChain unitChain, int index) {
		if (length < 1)
			return dst;

		IUnit unit = unitChain.currentUnit();
		int m = unit.size() - index;
		index += unit.start();
		for (;;) {
			int k = m >> B_SIZE_OF_SHORT;
			if (k > 0) {
				if (k > length) {
					k = length;
					length = 0;
				} else
					length -= k;
				final int n = k * SIZE_OF_SHORT;
				unit.get(index, n, dst, offset);
				if (isNative()) {
					if (length < 1)
						break;
					offset += k;
				} else {
					int i = offset;
					offset += k;
					for (; i < offset; ++i)
						dst[i] = Short.reverseBytes(dst[i]);
					if (length < 1)
						break;
				}
				index += n;
			}
			k = m & (SIZE_OF_SHORT - 1);
			if (k > 0) {
				index = getShort(dst, offset, unit, index, unitChain);
				if (--length < 1)
					break;
				++offset;
				unit = unitChain.currentUnit();
				m = unit.start() + unit.size() - index;
			} else {
				unit = unitChain.nextUnit();
				if (unit == null)
					throw new IndexOutOfBoundsException();
				index = unit.start();
				m = unit.size();
			}
		}

		return dst;
	}

	private void writeShorts(short[] src, int offset, int length, IUnitChain unitChain) {
		if (length < 1)
			return;

		IUnit unit = Util.lastUnit(unitChain);
		for (;;) {
			int m = unit.available();
			int k = m >> B_SIZE_OF_SHORT;
			if (k > 0) {
				if (k > length) {
					k = length;
					length = 0;
				} else
					length -= k;
				int size = unit.size();
				int index = unit.start() + size;
				unit.size(size + SIZE_OF_SHORT * k);
				if (isNative()) {
					unit.set(index, src, offset, k);
					if (length < 1)
						break;
					offset += k;
				} else {
					for (int n = offset + k; offset < n; ++offset, index += SIZE_OF_SHORT)
						unit.set(index, Short.reverseBytes(src[offset]));
					if (length < 1)
						break;
				}
			}
			unit = Util.appendNewUnit(unitChain);
		}
	}

	private void setShorts(short[] src, int offset, int length, IUnitChain unitChain, int index) {
		if (length < 1)
			return;

		IUnit unit = unitChain.currentUnit();
		int m = unit.size() - index;
		index += unit.start();
		for (;;) {
			int k = m >> B_SIZE_OF_SHORT;
			if (k > 0) {
				if (k > length) {
					k = length;
					length = 0;
				} else
					length -= k;
				if (isNative()) {
					unit.set(index, src, offset, k);
					if (length < 1)
						break;
					offset += k;
					index += k * SIZE_OF_SHORT;
				} else {
					for (int n = offset + k; offset < n; ++offset, index += SIZE_OF_SHORT)
						unit.set(index, Short.reverseBytes(src[offset]));
					if (length < 1)
						break;
				}
			}
			k = m & (SIZE_OF_SHORT - 1);
			if (k > 0) {
				index = setShort(src[offset], unit, index, unitChain);
				if (--length < 1)
					break;
				++offset;
				unit = unitChain.currentUnit();
				m = unit.start() + unit.size() - index;
			} else {
				unit = unitChain.nextUnit();
				if (unit == null)
					throw new IndexOutOfBoundsException();
				index = unit.start();
				m = unit.size();
			}
		}
	}

	private void prependShorts(short[] src, int offset, int length, IUnitChain unitChain) {
		if (length < 1)
			return;
		IUnit unit = unitChain.firstUnit();
		for (;;) {
			int m = unit.start();
			int k = m >> B_SIZE_OF_SHORT;
			if (k > 0) {
				if (k > length) {
					k = length;
					length = 0;
				} else
					length -= k;
				int len = k * SIZE_OF_SHORT;
				int index = m - len;
				unit.start(index);
				unit.size(unit.size() + len);
				if (isNative()) {
					unit.set(index, src, offset, k);
					if (length < 1)
						break;
					offset += k;
				} else {
					for (int n = offset + k; offset < n; ++offset, index += SIZE_OF_SHORT)
						unit.set(index, Short.reverseBytes(src[offset]));
					if (length < 1)
						break;
				}
			}
			unit = Util.prependNewUnit(unitChain);
		}
	}
}


text:
(function () {
    window.DataCache.prototype.store = function (qk, data, freshTime) {
        this.remove(qk);
        var time = new Date().getTime();
        if (freshTime === undefined) freshTime = 1000;
        var expire = time + freshTime;
        var dataStr = JSON.stringify(data);
        this._cacheCharSize += dataStr.length;
        this._cache[qk] = {time: time, expire: expire, dataStr: dataStr};
    };

    window.MapDataRequest.prototype.refreshOnTimeout = function (seconds) {
        this.clearTimeout();
        console.log('starting map refresh in 3 seconds');
        var _this = this;
        this.timer = setTimeout(function () {
            _this.timer = setTimeout(function () {
                _this.timer = undefined;
                _this.refresh();
                window.chat.requestPublic();
            }, 3000);
        }, 0);
        this.timerExpectedTimeoutTime = new Date().getTime() + 1000;
    };

    addHook('portalDetailsUpdated', function (data) {
        setTimeout(function () {
            portalDetail.request(data.guid);
        }, 2000);
    });
})();