mongoose-data-seed
Version:
Seed mongodb with data using mongoose models
491 lines (429 loc) • 25 kB
HTML
<html>
<head>
<meta charset="utf-8">
<base data-ice="baseUrl" href="../../../../">
<title data-ice="title">src/lib/core/installer.js | mongoose-data-seed</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
<script src="script/prettify/prettify.js"></script>
<script src="script/manual.js"></script>
<meta name="description" content="Seed mongodb with data using mongoose models"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="mongoose-data-seed"><meta property="twitter:description" content="Seed mongodb with data using mongoose models"></head>
<body class="layout-container" data-ice="rootContainer">
<header>
<a href="./">Home</a>
<a href="identifiers.html">Reference</a>
<a href="source.html">Source</a>
<a href="test.html" data-ice="testLink">Test</a>
<div class="search-box">
<span>
<img src="./image/search.png">
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
</span>
<ul class="search-result"></ul>
</div>
<a style="position:relative; top:3px;" href="https://github.com/sharvit/mongoose-data-seed"><img width="20px" src="./image/github.png"></a></header>
<nav class="navigation" data-ice="nav"><div>
<ul>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib">lib</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-config">config</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-configFilename">configFilename</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-defaultUserGeneratorConfig">defaultUserGeneratorConfig</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-systemConfigTemplate">systemConfigTemplate</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-systemSeederTemplate">systemSeederTemplate</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-commands">lib/commands</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-aliasToCommand">aliasToCommand</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-commandToFunction">commandToFunction</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getCommandAndArgvFromCli">getCommandAndArgvFromCli</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isAlias">isAlias</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-runCommand">runCommand</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-aliases">aliases</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-availableCommandsList">availableCommandsList</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-commands">commands</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-commandsMap">commandsMap</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-defaultCommand">defaultCommand</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-commands-generate">lib/commands/generate</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-generateSeeder">generateSeeder</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-help">help</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-index">index</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getOptions">getOptions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateOptions">validateOptions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-optionDefinitions">optionDefinitions</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-commands-help">lib/commands/help</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-help">help</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-usageGuide">usageGuide</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-commands-init">lib/commands/init</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/commands/init/installer-logger.js~InstallerLogger.html">InstallerLogger</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-help">help</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-index">index</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getOptions">getOptions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-promptMissingOptions">promptMissingOptions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-runinstaller">runinstaller</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-optionDefinitions">optionDefinitions</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-commands-run">lib/commands/run</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/commands/run/run-logger.js~RunLogger.html">RunLogger</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-help">help</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-index">index</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getOptions">getOptions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-run">run</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-optionDefinitions">optionDefinitions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-usageGuide">usageGuide</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-core">lib/core</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/core/installer-error.js~InstallerError.html">InstallerError</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/core/installer.js~Installer.html">Installer</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/core/md-seed-runner-error.js~MdSeedRunnerError.html">MdSeedRunnerError</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/core/md-seed-runner.js~MdSeedRunner.html">MdSeedRunner</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/core/seeder-generator.js~SeederGenerator.html">SeederGenerator</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-InstallerConfig">InstallerConfig</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-utils">lib/utils</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/utils/base-logger.js~BaseLogger.html">BaseLogger</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/utils/seeder.js~Seeder.html">Seeder</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-exit">exit</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getFolderNameFromPath">getFolderNameFromPath</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getObjectWithSelectedKeys">getObjectWithSelectedKeys</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-normalizeSeederFileName">normalizeSeederFileName</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-normalizeSeederName">normalizeSeederName</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateSeederTemplatePath">validateSeederTemplatePath</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateSeedersFolderName">validateSeedersFolderName</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-validateUserConfig">validateUserConfig</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ExitCodes">ExitCodes</a></span></span></li>
</ul>
</div>
</nav>
<div class="content" data-ice="content"><h1 data-ice="title">src/lib/core/installer.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">import fs from 'fs';
import path from 'path';
import memFs from 'mem-fs';
import editor from 'mem-fs-editor';
import { Subject } from 'rxjs';
import { defaultUserGeneratorConfig, systemSeederTemplate } from '../constants';
import config from '../config';
import InstallerError from './installer-error';
/**
* mongoose-data-seed installer
*
* @example
* // create installer
* const installer = new Installer({ seedersFolder: './seeders' });
*
* // run seeders
* const observable = installer.install();
*
* // subscribe logger
* observable.subscribe({
* next({ type, payload }) {
* switch (type) {
* case Installer.operations.START:
* console.log('Installer started!');
* break;
* case Installer.operations.SUCCESS:
* console.log('Installer finished successfully!');
* break;
* }
* },
* error({ type, payload }) {
* console.error(`Error: ${type}`);
* console.error(payload.error);
* }
* });
*/
export default class Installer {
/**
* @typedef {Object} InstallerConfig
* @property {string} seedersFolder Relative path to your seeders-folder.
* @property {?string} customSeederTemplate Relative path to your seeder-template
* if you would like to use your own seeders-template
*/
/**
* Installer operations constants
* @type {Object}
* @property {string} START Installation starts.
* @property {string} SUCCESS Installation succeed.
* @property {string} ERROR Installation finished with an error.
*/
static operations = {
START: 'START',
SUCCESS: 'SUCCESS',
ERROR: 'ERROR',
WRITE_USER_GENERETOR_CONFIG_START: 'WRITE_USER_GENERETOR_CONFIG_START',
WRITE_USER_GENERETOR_CONFIG_SUCCESS: 'WRITE_USER_GENERETOR_CONFIG_SUCCESS',
WRITE_USER_GENERETOR_CONFIG_ERROR: 'WRITE_USER_GENERETOR_CONFIG_ERROR',
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_START:
'CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_START',
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SUCCESS:
'CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SUCCESS',
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_ERROR:
'CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_ERROR',
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_FILE_EXISTS:
'CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_FILE_EXISTS',
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_NO_CUSTOM:
'CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_NO_CUSTOM',
CREATE_SEEDERS_FOLDER_START: 'CREATE_SEEDERS_FOLDER_START',
CREATE_SEEDERS_FOLDER_SUCCESS: 'CREATE_SEEDERS_FOLDER_SUCCESS',
CREATE_SEEDERS_FOLDER_ERROR: 'CREATE_SEEDERS_FOLDER_ERROR',
CREATE_SEEDERS_FOLDER_SKIP_FOLDER_EXISTS:
'CREATE_SEEDERS_FOLDER_SKIP_FOLDER_EXISTS',
WRITE_USER_CONFIG_START: 'WRITE_USER_CONFIG_START',
WRITE_USER_CONFIG_SUCCESS: 'WRITE_USER_CONFIG_SUCCESS',
WRITE_USER_CONFIG_ERROR: 'WRITE_USER_CONFIG_ERROR',
WRITE_USER_CONFIG_SKIP_FILE_EXISTS: 'WRITE_USER_CONFIG_SKIP_FILE_EXISTS',
};
/**
* Creates mongoose-data-seed installer
* @param {InstallerConfig} [config] Generator config
*/
constructor({
seedersFolder,
customSeederTemplate,
} = defaultUserGeneratorConfig) {
this._subject = new Subject();
this._initConfig({ seedersFolder, customSeederTemplate });
this._initMemFs();
}
/**
* Run installer - install `mongoose-data-seeder`
* @return {Observable}
* @see https://rxjs-dev.firebaseapp.com/api/index/class/Observable
*/
install() {
this._install();
return this._subject.asObservable();
}
/**
* get the config that should be written into the `package.json`
* @return {InstallerConfig} generator config
*/
getGeneratorConfig() {
const {
userSeedersFolderName: seedersFolder,
customSeederTemplateFilename: customSeederTemplate,
} = this.config;
const generatorConfig = { seedersFolder };
if (customSeederTemplate) {
generatorConfig.customSeederTemplate = customSeederTemplate;
}
return generatorConfig;
}
/*
Private methods
*/
/**
* Initiate this.config
* @param {InstallerConfig} config generator config
*/
_initConfig({ seedersFolder, customSeederTemplate }) {
/**
* Full configuration object
* @type {Object}
* @property {string} userPackageJsonPath path to the user package.json file.
* @property {?string} customSeederTemplateFilename custom seeder template filename.
* @property {?string} customSeederTemplatePath custom seeder template path.
* @property {string} userSeedersFolderName seeders folder name.
* @property {string} userSeedersFolderPath seeders folder path.
* @property {boolean} userConfigExists user has a config file?.
* @property {?string} userConfigFilename config file name.
* @property {?string} userConfigFilepath config file path.
* @property {string} configTemplatePath config template path.
*/
this.config = {
userPackageJsonPath: path.join(config.projectRoot, './package.json'),
customSeederTemplateFilename:
customSeederTemplate && customSeederTemplate,
customSeederTemplatePath:
customSeederTemplate &&
path.join(config.projectRoot, customSeederTemplate),
userSeedersFolderName: seedersFolder,
userSeedersFolderPath: path.join(config.projectRoot, seedersFolder),
userConfigExists: config.userConfigExists,
userConfigFilename: config.userConfigFilename,
userConfigFilepath: config.userConfigFilepath,
configTemplatePath: config.configTemplate,
};
}
/**
* Initiate the in-memory file-system
*/
_initMemFs() {
const store = memFs.create();
this._memFsEditor = editor.create(store);
}
/**
* Run the installation process
* @return {Promise}
*/
async _install() {
const { START, SUCCESS, ERROR } = Installer.operations;
try {
this._subject.next({ type: START });
await this._createCustomSeederTemplate();
await this._writeUserGeneratorConfigToPackageJson();
await this._createSeedersFolder();
await this._writeUserConfig();
this._subject.next({ type: SUCCESS });
this._subject.complete();
} catch (error) {
const { type = ERROR, payload = { error } } = error;
this._subject.error({ type, payload });
}
}
/**
* Commit the in-memory file changes
* @return {Promise}
*/
async _commitMemFsChanges() {
return new Promise(resolve => {
this._memFsEditor.commit(() => {
resolve();
});
});
}
/**
* Copy the package seeder-template to the user desired
* custom-seeder-template path if the user wants to use his own seeder-template
* @return {Promise} [description]
*/
async _createCustomSeederTemplate() {
const {
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_START,
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SUCCESS,
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_ERROR,
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_FILE_EXISTS,
CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_NO_CUSTOM,
} = Installer.operations;
const {
customSeederTemplateFilename,
customSeederTemplatePath,
} = this.config;
const payload = { customSeederTemplateFilename, customSeederTemplatePath };
const notify = type => this._subject.next({ type, payload });
try {
notify(CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_START);
if (!customSeederTemplatePath) {
return notify(CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_NO_CUSTOM);
}
if (fs.existsSync(customSeederTemplatePath)) {
notify(CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SKIP_FILE_EXISTS);
} else {
// copy template
this._memFsEditor.copy(systemSeederTemplate, customSeederTemplatePath);
// commit changes
await this._commitMemFsChanges();
notify(CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_SUCCESS);
}
} catch (error) {
throw new InstallerError({
type: CREATE_CUSTOM_SEEDER_TEMPLATE_FILE_ERROR,
payload,
error,
});
}
}
/**
* Write the config into the user package.json
*/
async _writeUserGeneratorConfigToPackageJson() {
const {
WRITE_USER_GENERETOR_CONFIG_START,
WRITE_USER_GENERETOR_CONFIG_SUCCESS,
WRITE_USER_GENERETOR_CONFIG_ERROR,
} = Installer.operations;
const { userPackageJsonPath: packageJsonPath } = this.config;
const payload = { packageJsonPath };
try {
this._subject.next({ type: WRITE_USER_GENERETOR_CONFIG_START, payload });
const packageJson = require(packageJsonPath);
packageJson.mdSeed = this.getGeneratorConfig();
this._memFsEditor.writeJSON(packageJsonPath, packageJson);
await this._commitMemFsChanges();
this._subject.next({
type: WRITE_USER_GENERETOR_CONFIG_SUCCESS,
payload,
});
} catch (error) {
throw new InstallerError({
type: WRITE_USER_GENERETOR_CONFIG_ERROR,
payload,
error,
});
}
}
/**
* Create the seeders folder
*/
async _createSeedersFolder() {
const {
CREATE_SEEDERS_FOLDER_START,
CREATE_SEEDERS_FOLDER_SUCCESS,
CREATE_SEEDERS_FOLDER_ERROR,
CREATE_SEEDERS_FOLDER_SKIP_FOLDER_EXISTS,
} = Installer.operations;
const {
userSeedersFolderPath: folderpath,
userSeedersFolderName: foldername,
} = this.config;
const payload = { folderpath, foldername };
try {
this._subject.next({ type: CREATE_SEEDERS_FOLDER_START, payload });
if (fs.existsSync(folderpath)) {
this._subject.next({
type: CREATE_SEEDERS_FOLDER_SKIP_FOLDER_EXISTS,
payload,
});
} else {
fs.mkdirSync(folderpath);
this._subject.next({ type: CREATE_SEEDERS_FOLDER_SUCCESS, payload });
}
} catch (error) {
throw new InstallerError({
type: CREATE_SEEDERS_FOLDER_ERROR,
payload,
error,
});
}
}
/**
* Write the `md-seed-config.js` into the root folder
*/
async _writeUserConfig() {
const {
WRITE_USER_CONFIG_START,
WRITE_USER_CONFIG_SUCCESS,
WRITE_USER_CONFIG_ERROR,
WRITE_USER_CONFIG_SKIP_FILE_EXISTS,
} = Installer.operations;
const {
userConfigExists: fileExists,
userConfigFilename: filename,
userConfigFilepath: filepath,
configTemplatePath,
} = this.config;
const payload = { fileExists, filename, filepath };
try {
this._subject.next({ type: WRITE_USER_CONFIG_START, payload });
if (fileExists === true) {
this._subject.next({
type: WRITE_USER_CONFIG_SKIP_FILE_EXISTS,
payload,
});
} else {
// copy template
this._memFsEditor.copy(configTemplatePath, filepath);
// commit changes
await this._commitMemFsChanges();
this._subject.next({ type: WRITE_USER_CONFIG_SUCCESS, payload });
}
} catch (error) {
throw new InstallerError({
type: WRITE_USER_CONFIG_ERROR,
payload,
error,
});
}
}
}
</code></pre>
</div>
<footer class="footer">
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>
<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>