Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement][plugins] Portable configurators for plugins to improve developer experience #386

Open
44 of 63 tasks
t2ym opened this issue Aug 30, 2020 · 5 comments
Open
44 of 63 tasks

Comments

@t2ym
Copy link
Owner

t2ym commented Aug 30, 2020

[Enhancement][plugins] Portable configurators for plugins to improve developer experience

Notes

  • With configurators, configurations which are not configurable in demo-config/ have to be configured in plugins/ directory since plugins in the demo/ directory are generated through the configurators
  • Configurations in demo-config/ are preprocessed by preprocess
    • Since preprocess is a text processor, target files can be incomplete as JavaScript scripts
const basePolicyModule /* @echo EQUAL *//* @echo SPACE *//* @extend basePolicyModule.js *//* @endextend */;
Policy.mergePolicyModules(
  { contextNormalizer, acl },
  basePolicyModule, // policy modules can be directly included here without declaring variables
);
  • The reason why preprocess is used and rollup is NOT applied
    • Full source level compatiblity with monolithic scripts
      • preprocess can produce any scripts which are byte-by-byte identical to their monolithic original ones
        • git diff outputs are kept meaningful for them
      • CommonJS modules need require(), whose bundler outputs are not very neat
      • ES modules can be imported only at the top level scope of modules, which is not suitable for non-module scripts with block scoped variables
      • Since decent portable configurators have been missing in thin-hook, it should be critical for your current build environments to consume plugin scripts that are textually compatible
    • Potential alternative approaches may use rollup for bundling and post-process the bundled scripts as non-module scripts surrounded by block scopes
      • rollup is too SEMANTIC to keep the output script controlled and readable
        • Variable names are unpredictably transcoded
      • Raw ES modules are NOT executed until the full page is loaded, which timing is too late for plugins to function
        • Browser extensions may capture load or DOMContentLoaded events to inject malicious code into the document
      • If policy modules are implemented as ES modules, they have to import all classes, objects, and variables in reference, which may be too awkward and inflexible for their objectives, compared with those simplistic and incomplete script fragments for @include

Design Issues

  • What is the difference between configuration and customization?
    • Handing parameters to components - configuration
    • Modifying sources - customization
    • Generating sources via templating - configuration or customization?
    • Is the difference crucial?
    • The objective is to minimize tasks, maximize flexibility, and keep reliability, which are partially contradictory
  • Extand application to backend components and tasks
    • No explicit changes on targetConfig is required to apply configurators to backend components
    • Is it OK to call them "plugins" as well? Are they "backend plugins" in contrast with "frontend plugins"?
  • Consideration on future expansion to plugins with dedicated NPM packages
    • Searching for plugins in node_modules as a fallback of plugins directory

Status

  • TODOs
    • backend plugins (names are tentative) - It is preferable for plugins/folder-name to match their plugin names
      • portable plugins (optional dependencies)
        • integrity-service-helpers
        • validation-console
        • cacheBundleGenerationJs or @thin-hook/cache-bundle-generation
        • cacheBundleUploadServiceJs or @thin-hook/cache-bundle-upload-service
        • serverJs or @thin-hook/server
        • errorReportServiceJs or @thin-hook/error-report-service
        • integrityServiceJs or @thin-hook/integrity-service
        • validationServiceJs or @thin-hook/validation-service
      • thin-hook project-specific plugins (devDependencies)
        • (postHtmlJs) or @thin-hook/post-html-js
    • clean up redundant devDependencies
  • demo-config/config.js
    • target-configurator npm package
      • class TargetConfig extends Configurable(GulpDefaultRegistry, 'thin-hook') {}
    • bound to targetConfig to prefer this to targetConfig
      • configurator
      • task functions
      • targets
    • targetConfig as a gulp custom registry
    • use gulp tasks instead of npm scripts in thin-hook/package.json
    • scoped plugins as npm packages
      • Notes
        • scoped plugins can have their own npm dependencies
          • they can be omitted from project/package.json
        • local plugins can be registered as npm dependencies as file:local-path/plugins/name
        • private scoped plugins can be registered as npm dependencies
      • search for scoped npm packages
      • scoped @thin-hook/examples plugin and dependencies
        • Notes
          • Since @thin-hook/examples and dependencies are not required for loaders of thin-hook, they are dev dependencies
        • as a dev dependency in package.json
          • resolve npm dependencies
        • register dependent plugins at init(targetConfig)
        • @thin-hook/script-examples
          • resolve npm dependencies
        • @thin-hook/module-examples
          • resolve npm dependencies
        • @thin-hook/module-examples-dependencies
          • resolve npm dependencies
    • path
      • root
      • config
    • url
      • root
      • components
      • mappings
      • reverseMappings - generated from mappings
    • task(pluginName)
      • check dependencies
      • show task display names
  • disable-devtools.js
    • configurator.js
      • targetCongig.mode.devtoolsDisabled
    • gulp task disable-devtools
  • hook-callback.js
    • configurator.js
      • targetConfig.mode.enableDebugging
      • policy.js
      • basePolicyModule.js
      • wildcardWhitelist.js
    • gulp task policy -- WORK IN PROGRESS
  • Other plugins: TBD

Directory Structure

thin-hook/
  plugins/
    disable-devtools/
      configurator.js
      ...
    policy/
      configurator.js
      hook-callback.js
      ...
    .../ - other plugins
  any-path/
    plugins/
      scoped-top-level-plugin/
        configurator.js
        package.json
      scoped-dependent-plugin/
        configurator.js
        package.json
      ...
  node_modules/
    @plugin-scope/
      scoped-plugin1/
        configurator.js
        package.json
      scoped-dependent-plugin1/
        configurator.js
        package.json
      ...
    @plugin-scope2/
      scoped-plugin2/
        configurator.js
        package.json
      scoped-dependent-plugin2/
        configurator.js
        package.json
      ...
  demo-config/
    config.js - overall configurations
    policy/
      policy.js
      basePolicyModule.js
      wildcardWhitelist.js
      ...
    .../ - other plugins
  demo/
    disable-devtools.js
    hook-callback.js
    ... - other plugins

Gulp tasks

  • @thin-hook/examples, policy - WORK IN PROGRESS
const targetConfig = require('./demo-config/config.js');
gulp.registry(targetConfig); 

gulp.task('@thin-hook/examples'); // register scoped plugin and its dependencies as NPM packages
gulp.task('policy'); // register gulp task 'policy'
  • other plugins

targetConfig

/*
@license https://github.com/t2ym/thin-hook/blob/master/LICENSE.md
Copyright (c) 2020 Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
const path = require('path');
const { GulpDefaultRegistry, Configurable } = require('target-configurator');

class TargetConfig extends Configurable(GulpDefaultRegistry, 'thin-hook') {
  // configure itself step by step
  _configure() {
    super._configure();
    Object.assign(this.path, {
      root: 'demo',
      backend: 'demo-backend',
      frontend: 'demo-frontend',
      keys: 'demo-keys',
      components: 'bower_components',
      encodedIndexHtml: 'index.html',
      decodedIndexHtml: 'original-index.html',
      hook: TargetConfig.packagePath,
    });
    Object.assign(this, { // dependent on this.path
      'thin-hook': {
        hook: require('../hook.js'/*path.resolve(this.path.hook, 'hook.js')*/),
      },
      url: {
        [TargetConfig.needResolution]: true,
        root: '/components/thin-hook/demo', // usually root path should be in an upper directory like '/'; this root is in a deep directory since it is a demo in a component
        components: '/components',
        mappings: () => {
          let mappings = [
            // [ fullPath, urlPath ] in directory path names
            [path.resolve(this.path.base, this.path.components), this.url.components], // highest priority in mapping
            [path.resolve(this.path.base, this.path.root), this.url.root],
            [this.path.hook, path.resolve(this.url.components, this.path.hook.split('/').pop())], // for hook.min.js
          ];
          this.url.reverseMappings = this.reverseMappings(mappings); // [ urlPath, fullPath ] in directory path names
          return mappings;
        },
      },
      server: {
        serverJs: 'demoServer.js',
        port: 8080,
        devToolsHostPort: '0.0.0.0:9229',
        concurrency: 4,
      },
      errorReportService: {
        port: 8081,
      },
      validationService: {
        port: 8082,
      },
      certificates: {
        generateCertSh: 'generate_cert.sh',
        CA: 'demoCA', // default value for openssl
      },
      mode: {
        enableDebugging: false,
        devtoolsDisabled: true,
      },
    });
    Object.assign(this, {
      commands: { // dependent on this.path, this.server, this.certificates, and this.commands itself
        [TargetConfig.needResolution]: true,
        "http": () => `concurrently -k -s all -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'httpServer', 'errorReportService', 'validationService')}`,
        "debug": () => `concurrently -k -s all -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'debugServer', 'errorReportService', 'validationService')}`,
        "https": () => `concurrently -k -s all -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'httpsServer', 'errorReportService', 'validationService')}`,
        "cache-bundle": () => `concurrently -k --kill-others-on-fail -s first -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'buildServer', 'cacheBundleUploadService', 'cacheBundleGeneration')}`,
        "updateHtmlHash": () => `concurrently -k --kill-others-on-fail -s first -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'buildServer', 'cacheBundleUploadService', 'loadOnly')}`,
        "buildServer": `node ${path.resolve(this.path.base, this.path.backend, this.server.serverJs)} -p ${this.server.port} \\
          -m build -P https -H localhost:${this.server.port}`,
        "httpServer": `node ${path.resolve(this.path.base, this.path.backend, this.server.serverJs)} -p ${this.server.port} \\
          -m server -c ${this.server.concurrency} -H ${process.env['SERVER_HOST'] || 'localhost'}`,
        "httpsServer": `node ${path.resolve(this.path.base, this.path.backend, this.server.serverJs)} -p ${this.server.port} \\
          -m server -c ${this.server.concurrency} -P https -H ${process.env['SERVER_HOST'] || 'localhost'}:${this.server.port}`,
        "debugServer": `node --inspect-brk=${this.server.devToolsHostPort} ${path.resolve(this.path.base, this.path.backend, this.server.serverJs)} -p ${this.server.port} \\
          -m debug -c 1 -H ${process.env['SERVER_HOST'] || 'localhost'}`,
        "postHtml": () => `concurrently -k -s all -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'postHtmlServer', 'errorReportService', 'validationService')}`,
        "postHtmlServer": `node ${path.resolve(this.path.base, this.path.backend, this.server.serverJs)} -p ${this.server.port} \\
          -m server -c ${this.server.concurrency} -H ${process.env['SERVER_HOST'] || 'localhost'} --middleware ${path.resolve(this.path.base, this.path.backend, 'postHtml.js')}`,
        "errorReportService": `node ${path.resolve(this.path.base, this.path.backend, 'errorReportService.js')} -p ${this.errorReportService.port}`,
        "validationService": `node ${path.resolve(this.path.base, this.path.backend, 'validationService.js')} -p ${this.validationService.port} \\
          -m server -H ${process.env['VALIDATION_HOST'] || 'localhost'}`,
        "integrity-service-helpers": `cd ${path.resolve(this.path.base, this.path.backend, 'integrity-service-helpers')} && npm install`,
        "validation-console": `cd ${path.resolve(this.path.base, this.path.backend, 'validation-console')} && npm ci && npm run build`,
        "certificates": `cd ${path.resolve(this.path.base, this.path.keys)} && ./${this.certificates.generateCertSh} `,
        "clean-demo-certificates": `cd ${path.resolve(this.path.base, this.path.keys)} && rm -riv ${this.certificates.CA}`,
        "cacheBundleUploadService": `node ${path.resolve(this.path.base, this.path.backend, 'cacheBundleUploadService.js')}`,
        "cacheBundleGeneration": `node ${path.resolve(this.path.base, this.path.backend, 'cacheBundleGeneration.js')}`,
        "loadOnly": `node ${path.resolve(this.path.base, this.path.backend, 'cacheBundleGeneration.js')} loadOnly`,
        "test:attack": () => `concurrently -k -s all -c cyan,magentaBright,yellowBright \\
          ${this.getConcurrentlyArguments(this.commands, 'buildServer', 'cacheBundleUploadService', 'puppeteerAttackTest')}`,
        "puppeteerAttackTest": `node ${path.resolve(this.path.base, 'test/puppeteerAttackTest.js')}`,
        "frontend-modules": `cd ${path.resolve(this.path.base, this.path.root)} && npm install`,
        "frontend-modules-locked": `cd ${path.resolve(this.path.base, this.path.root)} && npm ci`,
      },
    });
    Object.assign(this, { // scoped plugins
      '@thin-hook/examples': {
        base: path.resolve(this.path.hook, 'examples'),
      },
      '@thin-hook/module-examples': {
        [TargetConfig.needResolution]: true,
        importMapsPath: () => path.resolve(this['@thin-hook/examples'].base, 'examples.importmap'),
        baseURL: '/components/'
      },
      '@thin-hook/module-examples-dependencies': {
        [TargetConfig.needResolution]: true,
        moduleDependenciesPath: () => path.resolve(this['@thin-hook/examples'].base, 'moduleDependencies.json'),
      },
    });
  }
}

const targetConfig = new TargetConfig();

module.exports = targetConfig;

Configurator

  • plugins/policy/configurator.js - WORK IN PROGRESS
const path = require('path');
const { preprocess } = require('preprocess');
const through = require('through2');

const pluginName = 'policy';

const configurator = function (targetConfig) {
  const configPath = path.resolve(this.path.base, this.path.config, pluginName);
  const destPath = path.resolve(this.path.base, this.path.root);
  const enableDebugging = this.mode.enableDebugging;
  const pluginDirname = __dirname;
  const sourceFile = this[pluginName] && this[pluginName].sourceFile
    ? this[pluginName].sourceFile
    : 'hook-callback.js';
  return () => this.gulp.src([ path.resolve(pluginDirname, sourceFile) ])
    // 1st pass
    .pipe(through.obj((file, enc, callback) => {
      let script = String(file.contents);
      script = preprocess(script,
        {
          SPACE: ' ',
          EQUAL: '=',
          SEMICOLON: ';',
          enableDebugging: typeof enableDebugging === 'undefined' ? 'false' : enableDebugging,
        },
        {
          type: 'js',
          srcDir: pluginDirname, // in plugins/policy/
        }
      );
      script = script.replace(/\/\* #include /g, '/* @include ');
      file.contents = Buffer.from(script);
      callback(null, file);
    }))
    // 2nd pass
    .pipe(through.obj((file, enc, callback) => {
      let script = String(file.contents);
      script = preprocess(script,
        {
          SPACE: ' ',
          EQUAL: '=',
          SEMICOLON: ';',
        },
        {
          type: 'js',
          srcDir: configPath, // in demo-config/policy/
        }
      );
      file.contents = Buffer.from(script);
      callback(null, file);
    }))
    .pipe(this.gulp.dest(destPath));
}

module.exports = {
  configurator,
  name: pluginName,
  dependencies: [],
};
  • plugins\cache-bundle-automation\configurator.js - WORK IN PROGRESS
const path = require('path');
const fs = require('fs');

const pluginName = 'cache-bundle-automation-json';

const configurator = function (targetConfig) {
  const destPath = path.resolve(this.path.base, this.path.root);
  const pluginDirname = __dirname;
  const sourceFile = this[pluginName] && this[pluginName].sourceFile
    ? this[pluginName].sourceFile
    : 'cache-bundle.json';
  return (done) => {
    const cacheAutomationScript = fs.readFileSync(this['automation-secret'].cacheAutomationScriptPath, 'utf-8');
    fs.writeFileSync(path.resolve(destPath, sourceFile), JSON.stringify({
      "version": this['get-version'].version,
      "https://thin-hook.localhost.localdomain/automation.json": JSON.stringify({
        "state": "init", // update state in the script to perform operations including reloading
        "serverSecret": this['automation-secret'].serverSecret,
        "script": cacheAutomationScript,
      }, null, 0)
    }, null, 2));
    done();
  };
}

module.exports = {
  configurator,
  name: pluginName,
  dependencies: [ 'get-version', 'automation-secret' ],
};
t2ym added a commit that referenced this issue Aug 30, 2020
t2ym added a commit that referenced this issue Sep 1, 2020
t2ym added a commit that referenced this issue Sep 2, 2020
t2ym added a commit that referenced this issue Sep 2, 2020
…nfigurators and more gulp tasks as plugins
t2ym added a commit that referenced this issue Sep 3, 2020
t2ym added a commit that referenced this issue Sep 7, 2020
t2ym added a commit that referenced this issue Sep 9, 2020
@t2ym
Copy link
Owner Author

t2ym commented Sep 9, 2020

この Issue のアクセス統計情報を Insights -> Traffic から確認すると、
Views 21, Unique visitors 1 で私自身以外に誰も閲覧していないように見えます。

t2ym added a commit that referenced this issue Sep 9, 2020
t2ym added a commit that referenced this issue Sep 9, 2020
t2ym added a commit that referenced this issue Sep 10, 2020
t2ym added a commit that referenced this issue Sep 11, 2020
t2ym added a commit that referenced this issue Sep 11, 2020
t2ym added a commit that referenced this issue Sep 13, 2020
t2ym added a commit that referenced this issue Sep 13, 2020
t2ym added a commit that referenced this issue Sep 18, 2020
…nnecessary functions from hook-callback.js
t2ym added a commit that referenced this issue Sep 24, 2020
… and Fix #393 [HTML/SVG] Add a flag to omit superfluous closing tags
@t2ym t2ym pinned this issue Sep 24, 2020
@t2ym
Copy link
Owner Author

t2ym commented Oct 1, 2020

[WIP] Dependency Graph

digraph dependencies {
  ratio = fill;
  rankdir="LR"
  node [fontsize=10, style=filled, shape=box, height=0.25]
  edge [fontsize=10]
  
  "injector-helpers"[color="0.590 0.273 1.000"]
  "node_modules/*"[color="0.408 0.498 1.000"]
  "injector-helpers" -> "node_modules/*"
  "plugins/target-injector/package.json"[color="0.408 0.498 1.000"]
  "injector-helpers" -> "plugins/target-injector/package.json"
  "this.inject.components.HtmlInjectionHandlerFactory" -> "injector-helpers"[color="0.002 0.999 0.999"]
  "this.inject.components.InjectionHandlerBase" -> "injector-helpers"[color="0.002 0.999 0.999"]
  "this.inject.components.Injector" -> "injector-helpers"[color="0.002 0.999 0.999"]
  "this.inject.components.JsInjectionHandlerFactory" -> "injector-helpers"[color="0.002 0.999 0.999"]
  "this.injector-helpers.done" -> "injector-helpers"[color="0.002 0.999 0.999"]

  "clean-gzip-json"[color="0.590 0.273 1.000"]
  "this.clean-gzip-json.done" -> "clean-gzip-json"[color="0.002 0.999 0.999"]

  "get-version"[color="0.590 0.273 1.000"]
  "demo/original-index.html"[color="0.408 0.498 1.000"]
  "get-version" -> "demo/original-index.html"
  "this.get-version.done" -> "get-version"[color="0.002 0.999 0.999"]
  "this.get-version.version" -> "get-version"[color="0.002 0.999 0.999"]
  "get-version" -> "this.gulp.src"

  "generate-cert-sh"[color="0.590 0.273 1.000"]
  "demo-keys/generate_cert.sh"[color="0.408 0.498 1.000"]
  "demo-keys/generate_cert.sh" -> "generate-cert-sh"[color="0.002 0.999 0.999"]
  "plugins/generate-cert-sh/generate_cert.sh"[color="0.408 0.498 1.000"]
  "generate-cert-sh" -> "plugins/generate-cert-sh/generate_cert.sh"
  "generate-cert-sh" -> "this.certificates.CA"
  "generate-cert-sh" -> "this.certificates.DN.CN"
  "generate-cert-sh" -> "this.certificates.DN.OU"
  "generate-cert-sh" -> "this.certificates.DN.ST"
  "generate-cert-sh" -> "this.certificates.generateCertSh"
  "this.generate-cert-sh.done" -> "generate-cert-sh"[color="0.002 0.999 0.999"]
  "generate-cert-sh" -> "this.gulp.dest"
  "generate-cert-sh" -> "this.gulp.src"
  "generate-cert-sh" -> "this.path.keys"

  "certificates"[color="0.590 0.273 1.000"]
  "this.certificates.done" -> "certificates"[color="0.002 0.999 0.999"]

  "keys"[color="0.590 0.273 1.000"]
  "keys" -> "this.get-version.version"
  "this.keys.AES_GCM.ivLength" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.AES_GCM.keyLength" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.AES_GCM.sessionIdIvName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.AES_GCM.sessionIdKeyName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.AES_GCM.tagLength" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.ECDSA.privateKeyName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.ECDSA.publicKeyName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.RSA.keyBits" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.RSA.keyBytes" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.RSA.keyPairE" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.RSA.privateKeyName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.RSA.publicKeyName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.SHA256.hashBits" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.SHA256.hashBytes" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.SHA256.hashName" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.done" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.keysJSONPath" -> "keys"[color="0.002 0.999 0.999"]
  "this.keys.keysPath" -> "keys"[color="0.002 0.999 0.999"]
  "keys" -> "this.keys.noUpdate"

  "@thin-hook/demo-gulpfile-js"[color="0.590 0.273 1.000"]
  "demo/gulpfile.js"[color="0.408 0.498 1.000"]
  "demo/gulpfile.js" -> "@thin-hook/demo-gulpfile-js"[color="0.002 0.999 0.999"]
  "plugins/demo-gulpfile-js/gulpfile.js"[color="0.408 0.498 1.000"]
  "@thin-hook/demo-gulpfile-js" -> "plugins/demo-gulpfile-js/gulpfile.js"
  "@thin-hook/demo-gulpfile-js" -> "this.gulp.dest"
  "@thin-hook/demo-gulpfile-js" -> "this.gulp.src"
  "this[@thin-hook/demo-gulpfile-js].done" -> "@thin-hook/demo-gulpfile-js"[color="0.002 0.999 0.999"]

  "about-blank-redirector"[color="0.590 0.273 1.000"]
  "demo/about-blank-redirector.html"[color="0.408 0.498 1.000"]
  "demo/about-blank-redirector.html" -> "about-blank-redirector"[color="0.002 0.999 0.999"]
  "demo/about-blank-redirector.js"[color="0.408 0.498 1.000"]
  "demo/about-blank-redirector.js" -> "about-blank-redirector"[color="0.002 0.999 0.999"]
  "plugins/about-blank-redirector/about-blank-redirector.html"[color="0.408 0.498 1.000"]
  "about-blank-redirector" -> "plugins/about-blank-redirector/about-blank-redirector.html"
  "plugins/about-blank-redirector/about-blank-redirector.js"[color="0.408 0.498 1.000"]
  "about-blank-redirector" -> "plugins/about-blank-redirector/about-blank-redirector.js"
  "this.about-blank-redirector.done" -> "about-blank-redirector"[color="0.002 0.999 0.999"]
  "about-blank-redirector" -> "this.gulp.dest"
  "about-blank-redirector" -> "this.gulp.src"
  "this.no-hook-authorization.hash[demo/about-blank-redirector.js]" -> "about-blank-redirector"[color="0.002 0.999 0.999"]

  "content-loader-js"[color="0.590 0.273 1.000"]
  "demo/content-loader.js"[color="0.408 0.498 1.000"]
  "demo/content-loader.js" -> "content-loader-js"[color="0.002 0.999 0.999"]
  "plugins/content-loader-js/content-loader.js"[color="0.408 0.498 1.000"]
  "content-loader-js" -> "plugins/content-loader-js/content-loader.js"
  "this.content-loader-js.done" -> "content-loader-js"[color="0.002 0.999 0.999"]
  "content-loader-js" -> "this.gulp.dest"
  "content-loader-js" -> "this.gulp.src"
  "content-loader-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "content-loader-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "content-loader-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "content-loader-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "content-loader-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "content-loader-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "content-loader-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "this.no-hook-authorization.hash[demo/content-loader.js]" -> "content-loader-js"[color="0.002 0.999 0.999"]
  "content-loader-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "content-loader-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "mark-parsed-js"[color="0.590 0.273 1.000"]
  "demo/mark-parsed.js"[color="0.408 0.498 1.000"]
  "demo/mark-parsed.js" -> "mark-parsed-js"[color="0.002 0.999 0.999"]
  "plugins/mark-parsed-js/mark-parsed.js"[color="0.408 0.498 1.000"]
  "mark-parsed-js" -> "plugins/mark-parsed-js/mark-parsed.js"
  "mark-parsed-js" -> "this.gulp.dest"
  "mark-parsed-js" -> "this.gulp.src"
  "this.mark-parsed-js.done" -> "mark-parsed-js"[color="0.002 0.999 0.999"]
  "mark-parsed-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "this.no-hook-authorization.hash[demo/mark-parsed.js]" -> "mark-parsed-js"[color="0.002 0.999 0.999"]
  "mark-parsed-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "mark-parsed-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "script-hashes-js"[color="0.590 0.273 1.000"]
  "demo/script-hashes.js"[color="0.408 0.498 1.000"]
  "demo/script-hashes.js" -> "script-hashes-js"[color="0.002 0.999 0.999"]
  "plugins/script-hashes-js/script-hashes.js"[color="0.408 0.498 1.000"]
  "script-hashes-js" -> "plugins/script-hashes-js/script-hashes.js"
  "script-hashes-js" -> "this.gulp.dest"
  "script-hashes-js" -> "this.gulp.src"
  "script-hashes-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "this.no-hook-authorization.hash[demo/script-hashes.js]" -> "script-hashes-js"[color="0.002 0.999 0.999"]
  "script-hashes-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "script-hashes-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "this.script-hashes-js.done" -> "script-hashes-js"[color="0.002 0.999 0.999"]

  "wrap-globals-js"[color="0.590 0.273 1.000"]
  "demo/wrap-globals.js"[color="0.408 0.498 1.000"]
  "demo/wrap-globals.js" -> "wrap-globals-js"[color="0.002 0.999 0.999"]
  "plugins/wrap-globals-js/wrap-globals.js"[color="0.408 0.498 1.000"]
  "wrap-globals-js" -> "plugins/wrap-globals-js/wrap-globals.js"
  "wrap-globals-js" -> "this.gulp.dest"
  "wrap-globals-js" -> "this.gulp.src"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "this.no-hook-authorization.hash[demo/wrap-globals.js]" -> "wrap-globals-js"[color="0.002 0.999 0.999"]
  "wrap-globals-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "wrap-globals-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "this.wrap-globals-js.done" -> "wrap-globals-js"[color="0.002 0.999 0.999"]

  "hook-native-api-js"[color="0.590 0.273 1.000"]
  "demo/hook-native-api.js"[color="0.408 0.498 1.000"]
  "demo/hook-native-api.js" -> "hook-native-api-js"[color="0.002 0.999 0.999"]
  "plugins/hook-native-api-js/hook-native-api.js"[color="0.408 0.498 1.000"]
  "hook-native-api-js" -> "plugins/hook-native-api-js/hook-native-api.js"
  "hook-native-api-js" -> "this.gulp.dest"
  "hook-native-api-js" -> "this.gulp.src"
  "this.hook-native-api-js.done" -> "hook-native-api-js"[color="0.002 0.999 0.999"]
  "hook-native-api-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "this.no-hook-authorization.hash[demo/hook-native-api.js]" -> "hook-native-api-js"[color="0.002 0.999 0.999"]
  "hook-native-api-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "hook-native-api-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "context-generator-js"[color="0.590 0.273 1.000"]
  "demo-config/context-generator-js/custom-context-generator.js"[color="0.408 0.498 1.000"]
  "context-generator-js" -> "demo-config/context-generator-js/custom-context-generator.js"
  "demo/context-generator.js"[color="0.408 0.498 1.000"]
  "demo/context-generator.js" -> "context-generator-js"[color="0.002 0.999 0.999"]
  "plugins/context-generator-js/context-generator.js"[color="0.408 0.498 1.000"]
  "context-generator-js" -> "plugins/context-generator-js/context-generator.js"
  "this.context-generator-js.done" -> "context-generator-js"[color="0.002 0.999 0.999"]
  "context-generator-js" -> "this.gulp.dest"
  "context-generator-js" -> "this.gulp.src"
  "context-generator-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "context-generator-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "context-generator-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "context-generator-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "context-generator-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "context-generator-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "this.no-hook-authorization.hash[demo/context-generator.js]" -> "context-generator-js"[color="0.002 0.999 0.999"]
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "context-generator-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "cache-bundle-js"[color="0.590 0.273 1.000"]
  "demo-config/cache-bundle-js/cache-policy.js"[color="0.408 0.498 1.000"]
  "cache-bundle-js" -> "demo-config/cache-bundle-js/cache-policy.js"
  "demo/cache-bundle.js"[color="0.408 0.498 1.000"]
  "demo/cache-bundle.js" -> "cache-bundle-js"[color="0.002 0.999 0.999"]
  "plugins/cache-bundle-js/cache-bundle.js"[color="0.408 0.498 1.000"]
  "cache-bundle-js" -> "plugins/cache-bundle-js/cache-bundle.js"
  "this.cache-bundle-js.done" -> "cache-bundle-js"[color="0.002 0.999 0.999"]
  "cache-bundle-js" -> "this.gulp.dest"
  "cache-bundle-js" -> "this.gulp.src"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "this.no-hook-authorization.hash[demo/cache-bundle.js]" -> "cache-bundle-js"[color="0.002 0.999 0.999"]
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "cache-bundle-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "cache-automation-js"[color="0.590 0.273 1.000"]
  "demo-config/cache-automation-js/automation.js"[color="0.408 0.498 1.000"]
  "cache-automation-js" -> "demo-config/cache-automation-js/automation.js"
  "demo-config/cache-automation-js/fetch-bundle-set.js"[color="0.408 0.498 1.000"]
  "cache-automation-js" -> "demo-config/cache-automation-js/fetch-bundle-set.js"
  "demo-config/cache-automation-js/navigate-menu-items.js"[color="0.408 0.498 1.000"]
  "cache-automation-js" -> "demo-config/cache-automation-js/navigate-menu-items.js"
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "demo/cache-automation.js" -> "cache-automation-js"[color="0.002 0.999 0.999"]
  "plugins/cache-automation-js/cache-about-blank-redirector.js"[color="0.408 0.498 1.000"]
  "cache-automation-js" -> "plugins/cache-automation-js/cache-about-blank-redirector.js"
  "plugins/cache-automation-js/cache-automation.js"[color="0.408 0.498 1.000"]
  "cache-automation-js" -> "plugins/cache-automation-js/cache-automation.js"
  "this.cache-automation-js.done" -> "cache-automation-js"[color="0.002 0.999 0.999"]
  "cache-automation-js" -> "this.gulp.dest"
  "cache-automation-js" -> "this.gulp.src"

  "automation-secret"[color="0.590 0.273 1.000"]
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "automation-secret" -> "demo/cache-automation.js"
  "this.automation-secret.authorization" -> "automation-secret"[color="0.002 0.999 0.999"]
  "this.automation-secret.cacheAutomationScriptPath" -> "automation-secret"[color="0.002 0.999 0.999"]
  "this.automation-secret.done" -> "automation-secret"[color="0.002 0.999 0.999"]
  "this.automation-secret.serverSecret" -> "automation-secret"[color="0.002 0.999 0.999"]

  "generate-import-maps"[color="0.590 0.273 1.000"]
  "demo-config/generate-import-maps/modules-private.importmap"[color="0.408 0.498 1.000"]
  "generate-import-maps" -> "demo-config/generate-import-maps/modules-private.importmap"
  "demo/modules-private.importmap"[color="0.408 0.498 1.000"]
  "generate-import-maps" -> "demo/modules-private.importmap"
  "demo/modules-private.importmap"[color="0.408 0.498 1.000"]
  "demo/modules-private.importmap" -> "generate-import-maps"[color="0.002 0.999 0.999"]
  "demo/modules.importmap"[color="0.408 0.498 1.000"]
  "demo/modules.importmap" -> "generate-import-maps"[color="0.002 0.999 0.999"]
  "demo/node_modules/*"[color="0.408 0.498 1.000"]
  "generate-import-maps" -> "demo/node_modules/*"
  "demo/package.json"[color="0.408 0.498 1.000"]
  "generate-import-maps" -> "demo/package.json"
  "this.generate-import-maps.done" -> "generate-import-maps"[color="0.002 0.999 0.999"]
  "generate-import-maps" -> "this.gulp.dest"
  "generate-import-maps" -> "this.gulp.src"
  "generate-import-maps" -> "this.import-maps.auxiliaryImportMap.imports.foo"
  "generate-import-maps" -> "this.import-maps.auxiliaryImportMap.imports.module-on-cdn"
  "generate-import-maps" -> "this.import-maps.importMapName"
  "generate-import-maps" -> "this.import-maps.privateImportMapName"
  "generate-import-maps" -> "this.path.base"
  "generate-import-maps" -> "this.path.root"
  "generate-import-maps" -> "this.url.mappings.length"
  "generate-import-maps" -> "this.url.mappings[0].length"
  "generate-import-maps" -> "this.url.mappings[0][0]"
  "generate-import-maps" -> "this.url.mappings[0][1]"
  "generate-import-maps" -> "this.url.mappings[1].length"
  "generate-import-maps" -> "this.url.mappings[1][0]"
  "generate-import-maps" -> "this.url.mappings[1][1]"

  "bundler-helpers"[color="0.590 0.273 1.000"]
  "this.bundler-helpers.done" -> "bundler-helpers"[color="0.002 0.999 0.999"]
  "this.bundles.components.bundlerContextGeneratorFactory" -> "bundler-helpers"[color="0.002 0.999 0.999"]
  "this.bundles.components.contextGeneratorHelper.post" -> "bundler-helpers"[color="0.002 0.999 0.999"]
  "this.bundles.components.contextGeneratorHelper.pre" -> "bundler-helpers"[color="0.002 0.999 0.999"]
  "this.bundles.components.hookTransformFactory" -> "bundler-helpers"[color="0.002 0.999 0.999"]
  "this.bundles.components.importMapperFactory" -> "bundler-helpers"[color="0.002 0.999 0.999"]

  "bundle-browserify"[color="0.590 0.273 1.000"]
  "demo/browserify-commonjs.js"[color="0.408 0.498 1.000"]
  "demo/browserify-commonjs.js" -> "bundle-browserify"[color="0.002 0.999 0.999"]
  "demo/commonjs.js"[color="0.408 0.498 1.000"]
  "bundle-browserify" -> "demo/commonjs.js"
  "demo/commonjs2.js"[color="0.408 0.498 1.000"]
  "bundle-browserify" -> "demo/commonjs2.js"
  "demo/package.json"[color="0.408 0.498 1.000"]
  "bundle-browserify" -> "demo/package.json"
  "node_modules/*"[color="0.408 0.498 1.000"]
  "bundle-browserify" -> "node_modules/*"
  "package.json"[color="0.408 0.498 1.000"]
  "bundle-browserify" -> "package.json"
  "this.bundle-browserify.done" -> "bundle-browserify"[color="0.002 0.999 0.999"]
  "bundle-browserify" -> "this.bundles.browserify.browserify"
  "bundle-browserify" -> "this.bundles.browserify.transform"
  "this.bundles.components.browserify" -> "bundle-browserify"[color="0.002 0.999 0.999"]
  "bundle-browserify" -> "this.bundles.components.bundlerContextGeneratorFactory"
  "bundle-browserify" -> "this.bundles.components.hookTransformFactory"
  "bundle-browserify" -> "this.bundles.enhanced-resolve.context"
  "bundle-browserify" -> "this.bundles.enhanced-resolve.options.extensions.length"
  "bundle-browserify" -> "this.bundles.enhanced-resolve.options.extensions[0]"
  "bundle-browserify" -> "this.bundles.enhanced-resolve.options.extensions[1]"
  "this.bundles.node-builtins-wrapper.browserify.*" -> "bundle-browserify"[color="0.002 0.999 0.999"]
  "bundle-browserify" -> "this.bundles.rollup"
  "bundle-browserify" -> "this.bundles.targets"
  "bundle-browserify" -> "this.bundles.thin-hook.compact"
  "bundle-browserify" -> "this.bundles.thin-hook.hookPrefix"
  "bundle-browserify" -> "this.bundles.thin-hook.initialScope"
  "bundle-browserify" -> "this.bundles.thin-hook.sourceMap"
  "bundle-browserify" -> "this.bundles.webpack"
  "bundle-browserify" -> "this.gulp.dest"
  "bundle-browserify" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "this.no-hook-authorization.hash[demo/browserify-commonjs.js]" -> "bundle-browserify"[color="0.002 0.999 0.999"]
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "bundle-browserify" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "bundle-browserify" -> "this.thin-hook.hook.contextGenerators"
  "bundle-browserify" -> "this.url.mappings.length"
  "bundle-browserify" -> "this.url.mappings[0].length"
  "bundle-browserify" -> "this.url.mappings[0][0]"
  "bundle-browserify" -> "this.url.mappings[0][1]"
  "bundle-browserify" -> "this.url.mappings[1].length"
  "bundle-browserify" -> "this.url.mappings[1][0]"
  "bundle-browserify" -> "this.url.mappings[1][1]"
  "bundle-browserify" -> "this.url.mappings[2].length"
  "bundle-browserify" -> "this.url.mappings[2][0]"
  "bundle-browserify" -> "this.url.mappings[2][1]"
  "bundle-browserify" -> "this.url.reverseMappings.length"
  "bundle-browserify" -> "this.url.reverseMappings[0].length"
  "bundle-browserify" -> "this.url.reverseMappings[0][0]"
  "bundle-browserify" -> "this.url.reverseMappings[0][1]"
  "bundle-browserify" -> "this.url.reverseMappings[1].length"
  "bundle-browserify" -> "this.url.reverseMappings[1][0]"
  "bundle-browserify" -> "this.url.reverseMappings[1][1]"

  "bundle-webpack"[color="0.590 0.273 1.000"]
  "demo/commonjs.js"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/commonjs.js"
  "demo/commonjs2.js"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/commonjs2.js"
  "demo/es6-module.js"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/es6-module.js"
  "demo/es6-module2.js"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/es6-module2.js"
  "demo/es6-module3.js"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/es6-module3.js"
  "demo/package.json"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "demo/package.json"
  "demo/webpack-commonjs.js"[color="0.408 0.498 1.000"]
  "demo/webpack-commonjs.js" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "demo/webpack-es6-module.js"[color="0.408 0.498 1.000"]
  "demo/webpack-es6-module.js" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "node_modules/*"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "node_modules/*"
  "package.json"[color="0.408 0.498 1.000"]
  "bundle-webpack" -> "package.json"
  "this.bundle-webpack.done" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "bundle-webpack" -> "this.bundles.browserify"
  "bundle-webpack" -> "this.bundles.components.browserify"
  "bundle-webpack" -> "this.bundles.components.bundlerContextGeneratorFactory"
  "bundle-webpack" -> "this.bundles.components.contextGeneratorHelper"
  "bundle-webpack" -> "this.bundles.components.hookTransformFactory"
  "bundle-webpack" -> "this.bundles.components.importMapperFactory"
  "bundle-webpack" -> "this.bundles.components.webpack.LoaderOptionsPlugin"
  "this.bundles.components.webpackStream" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "bundle-webpack" -> "this.bundles.enhanced-resolve.context"
  "bundle-webpack" -> "this.bundles.enhanced-resolve.options.extensions.length"
  "bundle-webpack" -> "this.bundles.enhanced-resolve.options.extensions[0]"
  "bundle-webpack" -> "this.bundles.enhanced-resolve.options.extensions[1]"
  "this.bundles.node-builtins-wrapper.webpack.*" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "bundle-webpack" -> "this.bundles.rollup"
  "bundle-webpack" -> "this.bundles.targets"
  "bundle-webpack" -> "this.bundles.thin-hook.compact"
  "bundle-webpack" -> "this.bundles.thin-hook.hookPrefix"
  "bundle-webpack" -> "this.bundles.thin-hook.initialScope"
  "bundle-webpack" -> "this.bundles.thin-hook.sourceMap"
  "bundle-webpack" -> "this.bundles.webpack.options"
  "bundle-webpack" -> "this.gulp.dest"
  "bundle-webpack" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/browserify-commonjs.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "this.no-hook-authorization.hash[demo/webpack-commonjs.js]" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "this.no-hook-authorization.hash[demo/webpack-es6-module.js]" -> "bundle-webpack"[color="0.002 0.999 0.999"]
  "bundle-webpack" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "bundle-webpack" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "bundle-webpack" -> "this.thin-hook.hook.contextGenerators"
  "bundle-webpack" -> "this.url.mappings.length"
  "bundle-webpack" -> "this.url.mappings[0].length"
  "bundle-webpack" -> "this.url.mappings[0][0]"
  "bundle-webpack" -> "this.url.mappings[0][1]"
  "bundle-webpack" -> "this.url.mappings[1].length"
  "bundle-webpack" -> "this.url.mappings[1][0]"
  "bundle-webpack" -> "this.url.mappings[1][1]"
  "bundle-webpack" -> "this.url.mappings[2].length"
  "bundle-webpack" -> "this.url.mappings[2][0]"
  "bundle-webpack" -> "this.url.mappings[2][1]"
  "bundle-webpack" -> "this.url.reverseMappings.length"
  "bundle-webpack" -> "this.url.reverseMappings[0].length"
  "bundle-webpack" -> "this.url.reverseMappings[0][0]"
  "bundle-webpack" -> "this.url.reverseMappings[0][1]"
  "bundle-webpack" -> "this.url.reverseMappings[1].length"
  "bundle-webpack" -> "this.url.reverseMappings[1][0]"
  "bundle-webpack" -> "this.url.reverseMappings[1][1]"

  "bundle-rollup"[color="0.590 0.273 1.000"]
  "demo/es6-module.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/es6-module.js"
  "demo/es6-module2.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/es6-module2.js"
  "demo/es6-module3.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/es6-module3.js"
  "demo/moduleDependencies.json"[color="0.408 0.498 1.000"]
  "demo/moduleDependencies.json" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "demo/modules.importmap"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/modules.importmap"
  "demo/modules/module1.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/modules/module1.js"
  "demo/modules/module2.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/modules/module2.js"
  "demo/modules/module3.js"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/modules/module3.js"
  "demo/node_modules/*"[color="0.408 0.498 1.000"]
  "bundle-rollup" -> "demo/node_modules/*"
  "demo/rollup-es6-module.js"[color="0.408 0.498 1.000"]
  "demo/rollup-es6-module.js" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "demo/rollup-module1.js"[color="0.408 0.498 1.000"]
  "demo/rollup-module1.js" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "this.bundle-rollup.done" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "bundle-rollup" -> "this.bundles.browserify.configurator"
  "bundle-rollup" -> "this.bundles.components.browserify"
  "bundle-rollup" -> "this.bundles.components.bundlerContextGeneratorFactory"
  "bundle-rollup" -> "this.bundles.components.contextGeneratorHelper.post"
  "bundle-rollup" -> "this.bundles.components.contextGeneratorHelper.pre"
  "bundle-rollup" -> "this.bundles.components.hookTransformFactory"
  "bundle-rollup" -> "this.bundles.components.importMapperFactory"
  "this.bundles.components.rollup.VERSION" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "this.bundles.components.rollup.rollup" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "this.bundles.components.rollup.watch" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "this.bundles.components.rollupPluginBrowserifyTransform" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "bundle-rollup" -> "this.bundles.components.webpackStream"
  "bundle-rollup" -> "this.bundles.enhanced-resolve.options.extensions.length"
  "bundle-rollup" -> "this.bundles.enhanced-resolve.options.extensions[0]"
  "bundle-rollup" -> "this.bundles.enhanced-resolve.options.extensions[1]"
  "bundle-rollup" -> "this.bundles.node-builtins-wrapper.browserify"
  "this.bundles.node-builtins-wrapper.rollup" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "bundle-rollup" -> "this.bundles.node-builtins-wrapper.webpack"
  "bundle-rollup" -> "this.bundles.rollup.configurator"
  "bundle-rollup" -> "this.bundles.rollup.inputOptions"
  "bundle-rollup" -> "this.bundles.rollup.outputOptions"
  "bundle-rollup" -> "this.bundles.targets.length"
  "bundle-rollup" -> "this.bundles.targets[0].bundler"
  "bundle-rollup" -> "this.bundles.targets[1].bundler"
  "bundle-rollup" -> "this.bundles.targets[2].bundler"
  "bundle-rollup" -> "this.bundles.targets[3].bundler"
  "bundle-rollup" -> "this.bundles.targets[3].entryBase"
  "bundle-rollup" -> "this.bundles.targets[3].outputBase"
  "bundle-rollup" -> "this.bundles.targets[4].bundler"
  "bundle-rollup" -> "this.bundles.targets[4].entryBase"
  "bundle-rollup" -> "this.bundles.targets[4].outputBase"
  "bundle-rollup" -> "this.bundles.thin-hook.compact"
  "bundle-rollup" -> "this.bundles.thin-hook.hookPrefix"
  "bundle-rollup" -> "this.bundles.thin-hook.initialScope"
  "bundle-rollup" -> "this.bundles.thin-hook.sourceMap"
  "bundle-rollup" -> "this.bundles.webpack.configurator"
  "bundle-rollup" -> "this.import-maps.importMapName"
  "bundle-rollup" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/browserify-commonjs.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "this.no-hook-authorization.hash[demo/rollup-es6-module.js]" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "this.no-hook-authorization.hash[demo/rollup-module1.js]" -> "bundle-rollup"[color="0.002 0.999 0.999"]
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/webpack-commonjs.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/webpack-es6-module.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "bundle-rollup" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "bundle-rollup" -> "this.path.base"
  "bundle-rollup" -> "this.path.root"
  "bundle-rollup" -> "this.thin-hook.hook.contextGenerators"
  "bundle-rollup" -> "this.thin-hook.hook.parameters"
  "bundle-rollup" -> "this.thin-hook.hook.utils"
  "bundle-rollup" -> "this.url.mappings.length"
  "bundle-rollup" -> "this.url.mappings[0].length"
  "bundle-rollup" -> "this.url.mappings[0][0]"
  "bundle-rollup" -> "this.url.mappings[0][1]"
  "bundle-rollup" -> "this.url.mappings[1].length"
  "bundle-rollup" -> "this.url.mappings[1][0]"
  "bundle-rollup" -> "this.url.mappings[1][1]"

  "policy"[color="0.590 0.273 1.000"]
  "demo-config/policy/basePolicyModule.js"[color="0.408 0.498 1.000"]
  "policy" -> "demo-config/policy/basePolicyModule.js"
  "demo-config/policy/policy.js"[color="0.408 0.498 1.000"]
  "policy" -> "demo-config/policy/policy.js"
  "demo-config/policy/wildcardWhitelist.js"[color="0.408 0.498 1.000"]
  "policy" -> "demo-config/policy/wildcardWhitelist.js"
  "demo/hook-callback.js"[color="0.408 0.498 1.000"]
  "demo/hook-callback.js" -> "policy"[color="0.002 0.999 0.999"]
  "plugins/policy/DistinctSet.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/DistinctSet.js"
  "plugins/policy/GlobalMethodsWrapper.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/GlobalMethodsWrapper.js"
  "plugins/policy/Policy.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/Policy.js"
  "plugins/policy/SetMap.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/SetMap.js"
  "plugins/policy/Stack.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/Stack.js"
  "plugins/policy/StrictModeWrapper.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/StrictModeWrapper.js"
  "plugins/policy/Symbols.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/Symbols.js"
  "plugins/policy/__hook__.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/__hook__.js"
  "plugins/policy/__hook__acl.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/__hook__acl.js"
  "plugins/policy/__hook__min.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/__hook__min.js"
  "plugins/policy/errorReport.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/errorReport.js"
  "plugins/policy/hook-callback.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/hook-callback.js"
  "plugins/policy/hook-native-api.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/hook-native-api.js"
  "plugins/policy/hookBenchmark.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/hookBenchmark.js"
  "plugins/policy/mutation-observer.js"[color="0.408 0.498 1.000"]
  "policy" -> "plugins/policy/mutation-observer.js"
  "policy" -> "this.gulp.dest"
  "policy" -> "this.gulp.src"
  "policy" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "policy" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "policy" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "policy" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "policy" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "policy" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "policy" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/browserify-commonjs.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "this.no-hook-authorization.hash[demo/hook-callback.js]" -> "policy"[color="0.002 0.999 0.999"]
  "policy" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/rollup-es6-module.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/rollup-module1.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/webpack-commonjs.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/webpack-es6-module.js]"
  "policy" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "policy" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "policy" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"
  "policy" -> "this.policy.__hook__acl"
  "policy" -> "this.policy.__hook__callback"
  "policy" -> "this.policy.__hook__min"
  "this.policy.done" -> "policy"[color="0.002 0.999 0.999"]
  "policy" -> "this.policy.hookBenchmark"

  "disable-devtools"[color="0.590 0.273 1.000"]
  "demo/disable-devtools.js"[color="0.408 0.498 1.000"]
  "demo/disable-devtools.js" -> "disable-devtools"[color="0.002 0.999 0.999"]
  "plugins/disable-devtools/disable-devtools.js"[color="0.408 0.498 1.000"]
  "disable-devtools" -> "plugins/disable-devtools/disable-devtools.js"
  "this.disable-devtools.done" -> "disable-devtools"[color="0.002 0.999 0.999"]
  "disable-devtools" -> "this.gulp.dest"
  "disable-devtools" -> "this.gulp.src"
  "disable-devtools" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "disable-devtools" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "disable-devtools" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "disable-devtools" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "disable-devtools" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "disable-devtools" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/browserify-commonjs.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "this.no-hook-authorization.hash[demo/disable-devtools.js]" -> "disable-devtools"[color="0.002 0.999 0.999"]
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/hook-callback.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/rollup-es6-module.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/rollup-module1.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/webpack-commonjs.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/webpack-es6-module.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "disable-devtools" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "integrity-js"[color="0.590 0.273 1.000"]
  "demo-keys/keys.json"[color="0.408 0.498 1.000"]
  "integrity-js" -> "demo-keys/keys.json"
  "demo/integrity.js"[color="0.408 0.498 1.000"]
  "demo/integrity.js" -> "integrity-js"[color="0.002 0.999 0.999"]
  "plugins/integrity-js/integrity.js"[color="0.408 0.498 1.000"]
  "integrity-js" -> "plugins/integrity-js/integrity.js"
  "integrity-js" -> "this.gulp.dest"
  "integrity-js" -> "this.gulp.src"
  "this.integrity-js.done" -> "integrity-js"[color="0.002 0.999 0.999"]
  "integrity-js" -> "this.keys.ECDSA.publicKeyName"
  "integrity-js" -> "this.keys.RSA.publicKeyName"
  "integrity-js" -> "this.keys.keysJSONPath"
  "integrity-js" -> "this.no-hook-authorization.hash[(function write2() { console.log(\"no-hook script tag via document.write\"); })()]"
  "integrity-js" -> "this.no-hook-authorization.hash[(function write4() { console.log(\"no-hook script tag in div tag via document.write\"); })()]"
  "integrity-js" -> "this.no-hook-authorization.hash[(function writeln2() { console.log(\"no-hook script tag via document.writeln\"); })()]"
  "integrity-js" -> "this.no-hook-authorization.hash[(function writeln4() { console.log(\"no-hook script tag in div tag via document.writeln\"); })()]"
  "integrity-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline cors]"
  "integrity-js" -> "this.no-hook-authorization.hash[/components/thin-hook/demo/ inline hooked eval results]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/about-blank-redirector.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/browserify-commonjs.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/cache-bundle.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/content-loader.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/context-generator.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/disable-devtools.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/hook-callback.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/hook-native-api.js]"
  "this.no-hook-authorization.hash[demo/integrity.js]" -> "integrity-js"[color="0.002 0.999 0.999"]
  "integrity-js" -> "this.no-hook-authorization.hash[demo/mark-parsed.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/rollup-es6-module.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/rollup-module1.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/script-hashes.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/webpack-commonjs.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/webpack-es6-module.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[demo/wrap-globals.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[https://cdnjs.cloudflare.com/ajax/libs/vis/4.18.1/vis.min.js]"
  "integrity-js" -> "this.no-hook-authorization.hash[location = \"about:blank\";]"

  "dummy-integrity"[color="0.590 0.273 1.000"]
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "dummy-integrity" -> "demo/cache-automation.js"
  "demo/integrity.json"[color="0.408 0.498 1.000"]
  "demo/integrity.json" -> "dummy-integrity"[color="0.002 0.999 0.999"]
  "dummy-integrity" -> "this.automation-secret.cacheAutomationScriptPath"
  "dummy-integrity" -> "this.automation-secret.serverSecret"
  "this.dummy-integrity.done" -> "dummy-integrity"[color="0.002 0.999 0.999"]
  "dummy-integrity" -> "this.get-version.version"

  "cache-bundle-automation-json"[color="0.590 0.273 1.000"]
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "cache-bundle-automation-json" -> "demo/cache-automation.js"
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "demo/cache-bundle.json" -> "cache-bundle-automation-json"[color="0.002 0.999 0.999"]
  "cache-bundle-automation-json" -> "this.automation-secret.cacheAutomationScriptPath"
  "cache-bundle-automation-json" -> "this.automation-secret.serverSecret"
  "this.cache-bundle-automation-json.done" -> "cache-bundle-automation-json"[color="0.002 0.999 0.999"]
  "cache-bundle-automation-json" -> "this.get-version.version"

  "script-hashes"[color="0.590 0.273 1.000"]
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "script-hashes" -> "demo/cache-bundle.json"
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "demo/cache-bundle.json" -> "script-hashes"[color="0.002 0.999 0.999"]
  "script-hashes" -> "this.gulp.dest"
  "script-hashes" -> "this.gulp.src"
  "this.script-hashes.SCRIPT_HASHES_PSEUDO_URL" -> "script-hashes"[color="0.002 0.999 0.999"]
  "this.script-hashes.done" -> "script-hashes"[color="0.002 0.999 0.999"]

  "script-hashes-integrity"[color="0.590 0.273 1.000"]
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "script-hashes-integrity" -> "demo/cache-bundle.json"
  "demo/index.html"[color="0.408 0.498 1.000"]
  "script-hashes-integrity" -> "demo/index.html"
  "demo/index.html"[color="0.408 0.498 1.000"]
  "demo/index.html" -> "script-hashes-integrity"[color="0.002 0.999 0.999"]
  "demo/original-index.html"[color="0.408 0.498 1.000"]
  "script-hashes-integrity" -> "demo/original-index.html"
  "demo/original-index.html"[color="0.408 0.498 1.000"]
  "demo/original-index.html" -> "script-hashes-integrity"[color="0.002 0.999 0.999"]
  "demo/script-hashes.js"[color="0.408 0.498 1.000"]
  "script-hashes-integrity" -> "demo/script-hashes.js"
  "script-hashes-integrity" -> "this.gulp.dest"
  "script-hashes-integrity" -> "this.gulp.src"
  "script-hashes-integrity" -> "this.path.decodedIndexHtml"
  "script-hashes-integrity" -> "this.path.encodedIndexHtml"
  "this.script-hashes-integrity.done" -> "script-hashes-integrity"[color="0.002 0.999 0.999"]
  "script-hashes-integrity" -> "this.script-hashes.SCRIPT_HASHES_PSEUDO_URL"

  "integrity-json"[color="0.590 0.273 1.000"]
  "bower_components/*"[color="0.408 0.498 1.000"]
  "integrity-json" -> "bower_components/*"
  "demo-config/integrity-json/targets.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo-config/integrity-json/targets.js"
  "demo/Function.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/Function.js"
  "demo/about-blank-redirector.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/about-blank-redirector.html"
  "demo/about-blank-redirector.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/about-blank-redirector.js"
  "demo/bootstrap.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/bootstrap.js"
  "demo/browserify-commonjs.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/browserify-commonjs.js"
  "demo/bundle.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/bundle.json"
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/cache-automation.js"
  "demo/cache-bundle.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/cache-bundle.js"
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/cache-bundle.json"
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "demo/cache-bundle.json" -> "integrity-json"[color="0.002 0.999 0.999"]
  "demo/commonjs.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/commonjs.js"
  "demo/commonjs2.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/commonjs2.js"
  "demo/content-loader.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/content-loader.js"
  "demo/context-generator.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/context-generator.js"
  "demo/disable-devtools.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/disable-devtools.js"
  "demo/empty-document.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/empty-document.html"
  "demo/es6-module.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/es6-module.js"
  "demo/es6-module2.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/es6-module2.js"
  "demo/es6-module3.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/es6-module3.js"
  "demo/es6-module4.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/es6-module4.js"
  "demo/exported.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/exported.html"
  "demo/generator.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/generator.js"
  "demo/global.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/global.js"
  "demo/gulpfile.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/gulpfile.js"
  "demo/hook-callback.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/hook-callback.js"
  "demo/hook-native-api.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/hook-native-api.js"
  "demo/hook-worker.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/hook-worker.js"
  "demo/index-fb.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/index-fb.html"
  "demo/inline-script.svg"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/inline-script.svg"
  "demo/integrity.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/integrity.js"
  "demo/integrity.json"[color="0.408 0.498 1.000"]
  "demo/integrity.json" -> "integrity-json"[color="0.002 0.999 0.999"]
  "demo/invalid-document.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/invalid-document.html"
  "demo/lhs.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/lhs.js"
  "demo/locales/bundle.de.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/bundle.de.json"
  "demo/locales/bundle.es.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/bundle.es.json"
  "demo/locales/bundle.fr.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/bundle.fr.json"
  "demo/locales/bundle.ja.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/bundle.ja.json"
  "demo/locales/bundle.zh-Hans.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/bundle.zh-Hans.json"
  "demo/locales/my-app.de.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-app.de.json"
  "demo/locales/my-app.es.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-app.es.json"
  "demo/locales/my-app.fr.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-app.fr.json"
  "demo/locales/my-app.ja.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-app.ja.json"
  "demo/locales/my-app.zh-Hans.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-app.zh-Hans.json"
  "demo/locales/my-view1.de.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view1.de.json"
  "demo/locales/my-view1.es.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view1.es.json"
  "demo/locales/my-view1.fr.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view1.fr.json"
  "demo/locales/my-view1.ja.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view1.ja.json"
  "demo/locales/my-view1.zh-Hans.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view1.zh-Hans.json"
  "demo/locales/my-view2.de.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view2.de.json"
  "demo/locales/my-view2.es.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view2.es.json"
  "demo/locales/my-view2.fr.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view2.fr.json"
  "demo/locales/my-view2.ja.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view2.ja.json"
  "demo/locales/my-view2.zh-Hans.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view2.zh-Hans.json"
  "demo/locales/my-view3.de.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view3.de.json"
  "demo/locales/my-view3.es.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view3.es.json"
  "demo/locales/my-view3.fr.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view3.fr.json"
  "demo/locales/my-view3.ja.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view3.ja.json"
  "demo/locales/my-view3.zh-Hans.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/locales/my-view3.zh-Hans.json"
  "demo/mark-parsed.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/mark-parsed.js"
  "demo/moduleDependencies.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/moduleDependencies.json"
  "demo/modules-private.importmap"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/modules-private.importmap"
  "demo/modules.importmap"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/modules.importmap"
  "demo/modules/module1.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/modules/module1.js"
  "demo/modules/module2.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/modules/module2.js"
  "demo/modules/module3.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/modules/module3.js"
  "demo/my-app.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-app.html"
  "demo/my-app.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-app.json"
  "demo/my-view1.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view1.html"
  "demo/my-view1.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view1.json"
  "demo/my-view2.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view2.html"
  "demo/my-view2.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view2.json"
  "demo/my-view3.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view3.html"
  "demo/my-view3.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/my-view3.json"
  "demo/no-hook-authorization.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/no-hook-authorization.js"
  "demo/node_modules/*"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/node_modules/*"
  "demo/normalize.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/normalize.js"
  "demo/package-lock.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/package-lock.json"
  "demo/package.json"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/package.json"
  "demo/rollup-es6-module.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/rollup-es6-module.js"
  "demo/rollup-module1.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/rollup-module1.js"
  "demo/script-hashes.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/script-hashes.js"
  "demo/shared-worker-client.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/shared-worker-client.js"
  "demo/shared-worker.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/shared-worker.js"
  "demo/spread.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/spread.js"
  "demo/sub-document.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/sub-document.html"
  "demo/sub-sub-document.html"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/sub-sub-document.html"
  "demo/unauthorized-no-hook-script.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/unauthorized-no-hook-script.js"
  "demo/unauthorized-no-hook-worker-script.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/unauthorized-no-hook-worker-script.js"
  "demo/web-worker-client.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/web-worker-client.js"
  "demo/web-worker-module-client.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/web-worker-module-client.js"
  "demo/web-worker-module.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/web-worker-module.js"
  "demo/web-worker.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/web-worker.js"
  "demo/webpack-commonjs.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/webpack-commonjs.js"
  "demo/webpack-es6-module.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/webpack-es6-module.js"
  "demo/wrap-globals.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/wrap-globals.js"
  "demo/xliff/bundle.de.xlf"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/xliff/bundle.de.xlf"
  "demo/xliff/bundle.es.xlf"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/xliff/bundle.es.xlf"
  "demo/xliff/bundle.fr.xlf"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/xliff/bundle.fr.xlf"
  "demo/xliff/bundle.ja.xlf"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/xliff/bundle.ja.xlf"
  "demo/xliff/bundle.zh-Hans.xlf"[color="0.408 0.498 1.000"]
  "integrity-json" -> "demo/xliff/bundle.zh-Hans.xlf"
  "hook.min.js"[color="0.408 0.498 1.000"]
  "integrity-json" -> "hook.min.js"
  "integrity-json" -> "this.get-version.version"
  "integrity-json" -> "this.gulp.dest"
  "integrity-json" -> "this.gulp.src"
  "this.integrity-json.done" -> "integrity-json"[color="0.002 0.999 0.999"]
  "integrity-json" -> "this.path.base"
  "integrity-json" -> "this.path.components"
  "integrity-json" -> "this.path.decodedIndexHtml"
  "integrity-json" -> "this.path.encodedIndexHtml"
  "integrity-json" -> "this.path.hook"
  "integrity-json" -> "this.path.root"
  "integrity-json" -> "this.url.mappings.length"
  "integrity-json" -> "this.url.mappings[0].length"
  "integrity-json" -> "this.url.mappings[0][0]"
  "integrity-json" -> "this.url.mappings[0][1]"
  "integrity-json" -> "this.url.mappings[1].length"
  "integrity-json" -> "this.url.mappings[1][0]"
  "integrity-json" -> "this.url.mappings[1][1]"
  "integrity-json" -> "this.url.mappings[2].length"
  "integrity-json" -> "this.url.mappings[2][0]"
  "integrity-json" -> "this.url.mappings[2][1]"

  "gzip-json"[color="0.590 0.273 1.000"]
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "gzip-json" -> "demo/cache-bundle.json"
  "demo/cache-bundle.json.gz"[color="0.408 0.498 1.000"]
  "demo/cache-bundle.json.gz" -> "gzip-json"[color="0.002 0.999 0.999"]
  "demo/integrity.json"[color="0.408 0.498 1.000"]
  "gzip-json" -> "demo/integrity.json"
  "demo/integrity.json.gz"[color="0.408 0.498 1.000"]
  "demo/integrity.json.gz" -> "gzip-json"[color="0.002 0.999 0.999"]
  "gzip-json" -> "this.gulp.dest"
  "gzip-json" -> "this.gulp.src"
  "this.gzip-json.done" -> "gzip-json"[color="0.002 0.999 0.999"]

  "clean-frontend"[color="0.590 0.273 1.000"]
  "this.clean-frontend.done" -> "clean-frontend"[color="0.002 0.999 0.999"]
  "clean-frontend" -> "this.path.base"
  "clean-frontend" -> "this.path.frontend"

  "frontend-components"[color="0.590 0.273 1.000"]
  "bower_components/*"[color="0.408 0.498 1.000"]
  "frontend-components" -> "bower_components/*"
  "demo-config/frontend-components/targets.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo-config/frontend-components/targets.js"
  "demo-frontend/*"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo-frontend/*"
  "demo-frontend/*"[color="0.408 0.498 1.000"]
  "demo-frontend/*" -> "frontend-components"[color="0.002 0.999 0.999"]
  "demo/about-blank-redirector.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/about-blank-redirector.js"
  "demo/bootstrap.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/bootstrap.js"
  "demo/browserify-commonjs.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/browserify-commonjs.js"
  "demo/bundle.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/bundle.json"
  "demo/cache-automation.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/cache-automation.js"
  "demo/cache-bundle.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/cache-bundle.js"
  "demo/cache-bundle.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/cache-bundle.json"
  "demo/cache-bundle.json.gz"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/cache-bundle.json.gz"
  "demo/commonjs.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/commonjs.js"
  "demo/commonjs2.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/commonjs2.js"
  "demo/content-loader.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/content-loader.js"
  "demo/context-generator.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/context-generator.js"
  "demo/disable-devtools.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/disable-devtools.js"
  "demo/exported.html"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/exported.html"
  "demo/hook-callback.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/hook-callback.js"
  "demo/hook-native-api.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/hook-native-api.js"
  "demo/hook-worker.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/hook-worker.js"
  "demo/index.html"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/index.html"
  "demo/integrity.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/integrity.js"
  "demo/integrity.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/integrity.json"
  "demo/integrity.json.gz"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/integrity.json.gz"
  "demo/locales/my-app.de.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-app.de.json"
  "demo/locales/my-app.es.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-app.es.json"
  "demo/locales/my-app.fr.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-app.fr.json"
  "demo/locales/my-app.ja.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-app.ja.json"
  "demo/locales/my-app.zh-Hans.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-app.zh-Hans.json"
  "demo/locales/my-view1.de.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view1.de.json"
  "demo/locales/my-view1.es.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view1.es.json"
  "demo/locales/my-view1.fr.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view1.fr.json"
  "demo/locales/my-view1.ja.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view1.ja.json"
  "demo/locales/my-view1.zh-Hans.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view1.zh-Hans.json"
  "demo/locales/my-view2.de.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view2.de.json"
  "demo/locales/my-view2.es.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view2.es.json"
  "demo/locales/my-view2.fr.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view2.fr.json"
  "demo/locales/my-view2.ja.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view2.ja.json"
  "demo/locales/my-view2.zh-Hans.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view2.zh-Hans.json"
  "demo/locales/my-view3.de.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view3.de.json"
  "demo/locales/my-view3.es.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view3.es.json"
  "demo/locales/my-view3.fr.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view3.fr.json"
  "demo/locales/my-view3.ja.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view3.ja.json"
  "demo/locales/my-view3.zh-Hans.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/locales/my-view3.zh-Hans.json"
  "demo/mark-parsed.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/mark-parsed.js"
  "demo/moduleDependencies.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/moduleDependencies.json"
  "demo/modules-private.importmap"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/modules-private.importmap"
  "demo/modules.importmap"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/modules.importmap"
  "demo/my-app.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/my-app.json"
  "demo/my-view1.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/my-view1.json"
  "demo/my-view2.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/my-view2.json"
  "demo/my-view3.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/my-view3.json"
  "demo/no-hook-authorization.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/no-hook-authorization.js"
  "demo/node_modules/*"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/node_modules/*"
  "demo/package-lock.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/package-lock.json"
  "demo/package.json"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/package.json"
  "demo/rollup-es6-module.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/rollup-es6-module.js"
  "demo/rollup-module1.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/rollup-module1.js"
  "demo/script-hashes.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/script-hashes.js"
  "demo/unauthorized-no-hook-script.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/unauthorized-no-hook-script.js"
  "demo/unauthorized-no-hook-worker-script.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/unauthorized-no-hook-worker-script.js"
  "demo/web-worker-module.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/web-worker-module.js"
  "demo/webpack-commonjs.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/webpack-commonjs.js"
  "demo/webpack-es6-module.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/webpack-es6-module.js"
  "demo/wrap-globals.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/wrap-globals.js"
  "demo/xliff/bundle.de.xlf"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/xliff/bundle.de.xlf"
  "demo/xliff/bundle.es.xlf"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/xliff/bundle.es.xlf"
  "demo/xliff/bundle.fr.xlf"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/xliff/bundle.fr.xlf"
  "demo/xliff/bundle.ja.xlf"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/xliff/bundle.ja.xlf"
  "demo/xliff/bundle.zh-Hans.xlf"[color="0.408 0.498 1.000"]
  "frontend-components" -> "demo/xliff/bundle.zh-Hans.xlf"
  "hook.min.js"[color="0.408 0.498 1.000"]
  "frontend-components" -> "hook.min.js"
  "this.frontend-components.done" -> "frontend-components"[color="0.002 0.999 0.999"]
  "frontend-components" -> "this.gulp.dest"
  "frontend-components" -> "this.gulp.src"
  "frontend-components" -> "this.path.base"
  "frontend-components" -> "this.path.components"
  "frontend-components" -> "this.path.decodedIndexHtml"
  "frontend-components" -> "this.path.frontend"
  "frontend-components" -> "this.path.hook"
  "frontend-components" -> "this.path.root"
  "frontend-components" -> "this.url.mappings.length"
  "frontend-components" -> "this.url.mappings[0].length"
  "frontend-components" -> "this.url.mappings[0][0]"
  "frontend-components" -> "this.url.mappings[0][1]"
  "frontend-components" -> "this.url.mappings[1].length"
  "frontend-components" -> "this.url.mappings[1][0]"
  "frontend-components" -> "this.url.mappings[1][1]"
  "frontend-components" -> "this.url.mappings[2].length"
  "frontend-components" -> "this.url.mappings[2][0]"
  "frontend-components" -> "this.url.mappings[2][1]"
  "frontend-components" -> "this.url.reverseMappings.length"
  "frontend-components" -> "this.url.reverseMappings[0].length"
  "frontend-components" -> "this.url.reverseMappings[0][0]"
  "frontend-components" -> "this.url.reverseMappings[0][1]"
  "frontend-components" -> "this.url.reverseMappings[1].length"
  "frontend-components" -> "this.url.reverseMappings[1][0]"
  "frontend-components" -> "this.url.reverseMappings[1][1]"
  "frontend-components" -> "this.url.reverseMappings[2].length"
  "frontend-components" -> "this.url.reverseMappings[2][0]"
  "frontend-components" -> "this.url.reverseMappings[2][1]"

  "gzip-frontend"[color="0.590 0.273 1.000"]
  "demo-config/gzip-frontend/targets.js"[color="0.408 0.498 1.000"]
  "gzip-frontend" -> "demo-config/gzip-frontend/targets.js"
  "demo-frontend/*"[color="0.408 0.498 1.000"]
  "gzip-frontend" -> "demo-frontend/*"
  "demo-frontend/*"[color="0.408 0.498 1.000"]
  "demo-frontend/*" -> "gzip-frontend"[color="0.002 0.999 0.999"]
  "gzip-frontend" -> "this.gulp.dest"
  "gzip-frontend" -> "this.gulp.src"
  "this.gzip-frontend.done" -> "gzip-frontend"[color="0.002 0.999 0.999"]
  "gzip-frontend" -> "this.path.base"
  "gzip-frontend" -> "this.path.encodedIndexHtml"
  "gzip-frontend" -> "this.path.frontend"
  "gzip-frontend" -> "this.url.root"

}

@t2ym
Copy link
Owner Author

t2ym commented Oct 1, 2020

t2ym added a commit that referenced this issue Oct 2, 2020
t2ym added a commit that referenced this issue Oct 4, 2020
…endency-graph to show dataflow instead of dependency
t2ym added a commit that referenced this issue Oct 9, 2020
t2ym added a commit that referenced this issue Oct 9, 2020
…ies in tracing and Add gulp --tracer option
t2ym added a commit that referenced this issue Oct 9, 2020
…ies in tracing and Add gulp --tracer option
t2ym added a commit that referenced this issue Oct 13, 2020
…end part) and demo-raw/ as the injection starting point
t2ym added a commit that referenced this issue Oct 13, 2020
…ection (frontend parts) and demo-raw/ as the injection starting point
t2ym added a commit that referenced this issue Oct 14, 2020
…till incomplete) as optionalDependencies
t2ym added a commit that referenced this issue Oct 18, 2020
t2ym added a commit that referenced this issue Oct 19, 2020
t2ym added a commit that referenced this issue Oct 19, 2020
t2ym added a commit that referenced this issue Oct 19, 2020
@t2ym
Copy link
Owner Author

t2ym commented Oct 24, 2020

npm@7 is incompatible with file: optional dependencies

Root Cause (with npm@7.0.3)

  • npm@7 does NOT install dependencies of file: dependencies in a dependent package but just makes symbolic links to them
    • while npm@6 installs dependencies of file: dependencies in a dependent package and makes symbolic links to them in the 2nd execution of npm i after the initial npm dependent-package-name, which skips installations of file: optional dependencies

Decent Workaround

  • Use npm@6 instead of npm@7

Inelegant Workaround for npm@7

  • Install thin-hook package: npm i thin-hook
  • Make a symbolic link to plugins: ln -s node_modules/thin-hook/plugins plugins
  • Add plugins as workspaces in the project's package.json and issue npm i
    • Note: "node_modules/thin-hook/plugins/plugin-name" does not work as a workspace
  • Issue npm i file:plugins/injector-helpers
    • Dependencies in different versions for workspaces are not properly installed with npm@7

Notes:

  • Still npm ci fails when the command tries to mkdir plugins, which is a symlink
    • node_modules/thin-hook/ becomes empty on the error
{
  "name": "thin-hook-npm-test10",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "BSD-2-Clause",
  "workspaces": [
    "plugins/about-blank-redirector",
    "plugins/automation-secret",
    "plugins/generate-cert-sh",
    "plugins/bundle-browserify",
    "plugins/bundle-rollup",
    "plugins/bundle-webpack",
    "plugins/bundler-helpers",
    "plugins/cache-automation-js",
    "plugins/cache-bundle-js",
    "plugins/certificates",
    "plugins/clean-frontend",
    "plugins/clean-gzip-json",
    "plugins/content-loader-js",
    "plugins/context-generator-js",
    "plugins/disable-devtools",
    "plugins/entry-page",
    "plugins/frontend-components",
    "plugins/generate-import-maps",
    "plugins/gzip-frontend",
    "plugins/gzip-json",
    "plugins/hook-min-js",
    "plugins/hook-native-api-js",
    "plugins/hook-worker-js",
    "plugins/inject",
    "plugins/injector-helpers",
    "plugins/integrity-js",
    "plugins/integrity-json",
    "plugins/keys",
    "plugins/mark-parsed-js",
    "plugins/no-hook-authorization",
    "plugins/policy",
    "plugins/script-hashes",
    "plugins/script-hashes-integrity",
    "plugins/script-hashes-js",
    "plugins/url-parameters",
    "plugins/wrap-globals-js"
  ],
  "dependencies": {
    "thin-hook": "^0.4.0-alpha.42"
  }
}

@t2ym
Copy link
Owner Author

t2ym commented Oct 24, 2020

Note: Node 15 is not recommended

Fix for Node 15 compatibility in generate-import-maps

  • Avoid //
diff --git a/plugins/generate-import-maps/configurator.js b/plugins/generate-import-maps/configurator.js
index bf54014c..8167fe9c 100644
--- a/plugins/generate-import-maps/configurator.js
+++ b/plugins/generate-import-maps/configurator.js
@@ -95,7 +95,7 @@ const configurator = function (targetConfig) {
         //  - Scoped import maps for "bare-specifier/" are copied to global imports so that "bare-specifier/path/module.js" can be resolved from outside of the module scope
         //  - **NOT** loaded via <script type="importmap" src="modules.importmap"></script> nor <script type="importmap">JSON</script> for the time being
       const projectDirectoryFileUrl = new URL(this.path.root + '/', `file://${this.path.base}/`);
-      const baseUrlPath = this.mapper(this.url.mappings, projectDirectoryFileUrl.pathname) + '/';
+      const baseUrlPath = (this.mapper(this.url.mappings, projectDirectoryFileUrl.pathname) + '/').replace(/\/\/$/, '/');
       const privateImportMapFileUrl = new URL(this['import-maps'].privateImportMapName, projectDirectoryFileUrl);
       const normalizedImportMapFilePath = new URL(this['import-maps'].importMapName, projectDirectoryFileUrl).pathname;
       const importMapInputs = [

Difference in Node 15

Welcome to Node.js v15.0.1.
Type ".help" for more information.
> new URL('abc', 'file:////').pathname
'//abc'
> 

Welcome to Node.js v14.5.0.
Type ".help" for more information.
> new URL('abc', 'file:////').pathname
'/abc'
> 

t2ym added a commit that referenced this issue Oct 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant