@docusaurus/core 0.0.0-4875 → 0.0.0-4879

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/beforeCli.mjs CHANGED
@@ -45,7 +45,6 @@ export default async function beforeCli() {
45
45
  // Check is in background so it's fine to use a small value like 1h
46
46
  // Use 0 for debugging
47
47
  updateCheckInterval: 1000 * 60 * 60,
48
- // updateCheckInterval: 0
49
48
  });
50
49
 
51
50
  // Hacky way to ensure we check for updates on first run
@@ -124,7 +123,7 @@ export default async function beforeCli() {
124
123
  console.log(docusaurusUpdateMessage);
125
124
  }
126
125
 
127
- // notify user if node version needs to be updated
126
+ // Notify user if node version needs to be updated
128
127
  if (!semver.satisfies(process.version, requiredVersion)) {
129
128
  logger.error('Minimum Node.js version not met :(');
130
129
  logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`;
@@ -11,12 +11,11 @@ module.exports = {
11
11
  'error',
12
12
  {
13
13
  patterns: [
14
- // prevent importing lodash in client bundle
15
- // prefer shipping vanilla JS
14
+ // Prevent importing lodash in client bundle for bundle size
16
15
  'lodash',
17
16
  'lodash.**',
18
17
  'lodash/**',
19
- // prevent importing server code in client bundle
18
+ // Prevent importing server code in client bundle
20
19
  '**/../babel/**',
21
20
  '**/../server/**',
22
21
  '**/../commands/**',
@@ -30,7 +30,7 @@ function createInlineHtmlBanner(baseUrl) {
30
30
  </div>
31
31
  `;
32
32
  }
33
- // fn needs to work for older browsers!
33
+ // Needs to work for older browsers!
34
34
  function createInlineScript(baseUrl) {
35
35
  return `
36
36
  window['${InsertBannerWindowAttribute}'] = true;
@@ -91,7 +91,6 @@ function BaseUrlIssueBanner() {
91
91
  export default function MaybeBaseUrlIssueBanner() {
92
92
  const { siteConfig: { baseUrl, baseUrlIssueBanner }, } = useDocusaurusContext();
93
93
  const { pathname } = useLocation();
94
- // returns true for the homepage during SSR
95
94
  const isHomePage = pathname === baseUrl;
96
95
  const enabled = baseUrlIssueBanner && isHomePage;
97
96
  return enabled ? <BaseUrlIssueBanner /> : null;
@@ -17,8 +17,7 @@ export const createStatefulLinksCollector = () => {
17
17
  };
18
18
  const Context = React.createContext({
19
19
  collectLink: () => {
20
- // noop by default for client
21
- // we only use the broken links checker server-side
20
+ // No-op for client. We only use the broken links checker server-side.
22
21
  },
23
22
  });
24
23
  export const useLinksCollector = () => useContext(Context);
@@ -22,9 +22,7 @@ if (ExecutionEnvironment.canUseDOM) {
22
22
  // We also preload async component to avoid first-load loading screen.
23
23
  const renderMethod = process.env.NODE_ENV === 'production' ? ReactDOM.hydrate : ReactDOM.render;
24
24
  preload(window.location.pathname).then(() => {
25
- renderMethod(
26
- // @ts-expect-error: https://github.com/staylor/react-helmet-async/pull/165
27
- <HelmetProvider>
25
+ renderMethod(<HelmetProvider>
28
26
  <BrowserRouter>
29
27
  <App />
30
28
  </BrowserRouter>
@@ -106,7 +106,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
106
106
  // eslint-disable-next-line jsx-a11y/anchor-has-content
107
107
  <a ref={innerRef} href={targetLink} {...(targetLinkUnprefixed &&
108
108
  !isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink}
109
- // avoid "React does not recognize the `activeClassName` prop on a DOM
109
+ // Avoid "React does not recognize the `activeClassName` prop on a DOM
110
110
  // element"
111
111
  {...(isNavLink && { isActive, activeClassName })}/>);
112
112
  }
@@ -7,15 +7,9 @@
7
7
  import useDocusaurusContext from './useDocusaurusContext';
8
8
  import { hasProtocol } from './isInternalUrl';
9
9
  function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolute = false } = {}) {
10
- if (!url) {
11
- return url;
12
- }
13
- // it never makes sense to add a base url to a local anchor url
14
- if (url.startsWith('#')) {
15
- return url;
16
- }
17
- // it never makes sense to add a base url to an url with a protocol
18
- if (hasProtocol(url)) {
10
+ // It never makes sense to add base url to a local anchor url, or one with a
11
+ // protocol
12
+ if (!url || url.startsWith('#') || hasProtocol(url)) {
19
13
  return url;
20
14
  }
21
15
  if (forcePrependBaseUrl) {
@@ -19,7 +19,7 @@ function mergeContexts({ parent, value, }) {
19
19
  // TODO deep merge this
20
20
  const data = { ...parent.data, ...value?.data };
21
21
  return {
22
- // nested routes are not supposed to override plugin attribute
22
+ // Nested routes are not supposed to override plugin attribute
23
23
  plugin: parent.plugin,
24
24
  data,
25
25
  };
@@ -56,7 +56,6 @@ async function doRender(locals) {
56
56
  const appHtml = ReactDOMServer.renderToString(
57
57
  // @ts-expect-error: we are migrating away from react-loadable anyways
58
58
  <Loadable.Capture report={(moduleName) => modules.add(moduleName)}>
59
- {/* @ts-expect-error: https://github.com/staylor/react-helmet-async/pull/165 */}
60
59
  <HelmetProvider context={helmetContext}>
61
60
  <StaticRouter location={location} context={routerContext}>
62
61
  <LinksCollectorProvider linksCollector={linksCollector}>
@@ -101,7 +101,7 @@ async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLast
101
101
  new react_loadable_ssr_addon_v5_slorber_1.default({
102
102
  filename: clientManifestPath,
103
103
  }),
104
- ].filter(Boolean),
104
+ ].filter((x) => Boolean(x)),
105
105
  });
106
106
  const allCollectedLinks = {};
107
107
  const headTags = {};
@@ -89,8 +89,9 @@ This behavior can have SEO impacts and create relative link issues.
89
89
  shelljs_1.default.echo('Skipping deploy on a pull request.');
90
90
  shelljs_1.default.exit(0);
91
91
  }
92
- // github.io indicates organization repos that deploy via default branch.
93
- // All others use gh-pages. Organization deploys looks like:
92
+ // github.io indicates organization repos that deploy via default branch. All
93
+ // others use gh-pages (either case can be configured actually, but we can
94
+ // make educated guesses). Organization deploys look like:
94
95
  // - Git repo: https://github.com/<organization>/<organization>.github.io
95
96
  // - Site url: https://<organization>.github.io
96
97
  const isGitHubPagesOrganizationDeploy = projectName.includes('.github.io');
@@ -174,7 +175,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
174
175
  if (!cliOptions.skipBuild) {
175
176
  // Build site, then push to deploymentBranch branch of specified repo.
176
177
  try {
177
- await runDeploy(await (0, build_1.build)(siteDir, cliOptions, false));
178
+ await (0, build_1.build)(siteDir, cliOptions, false).then(runDeploy);
178
179
  }
179
180
  catch (err) {
180
181
  logger_1.default.error('Deployment of the build output failed.');
@@ -34,7 +34,7 @@ async function start(siteDir, cliOptions) {
34
34
  siteDir,
35
35
  customConfigFilePath: cliOptions.config,
36
36
  locale: cliOptions.locale,
37
- localizePath: undefined, // should this be configurable?
37
+ localizePath: undefined, // Should this be configurable?
38
38
  });
39
39
  }
40
40
  // Process all related files as a prop.
@@ -32,7 +32,7 @@ async function eject({ siteDir, themePath, componentName, }) {
32
32
  const fromPath = path_1.default.join(themePath, componentName);
33
33
  const isDirectory = await isDir(fromPath);
34
34
  const globPattern = isDirectory
35
- ? // do we really want to copy all components?
35
+ ? // Do we really want to copy all components?
36
36
  path_1.default.join(fromPath, '*')
37
37
  : `${fromPath}.*`;
38
38
  const globPatternPosix = (0, utils_1.posixPath)(globPattern);
@@ -52,7 +52,6 @@ function filterIntermediateRoutes(routesInput) {
52
52
  function getAllBrokenLinks({ allCollectedLinks, routes, }) {
53
53
  const filteredRoutes = filterIntermediateRoutes(routes);
54
54
  const allBrokenLinks = lodash_1.default.mapValues(allCollectedLinks, (pageLinks, pagePath) => getPageBrokenLinks({ pageLinks, pagePath, routes: filteredRoutes }));
55
- // remove pages without any broken link
56
55
  return lodash_1.default.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0);
57
56
  }
58
57
  function getBrokenLinksErrorMessage(allBrokenLinks) {
@@ -14,37 +14,18 @@ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
14
  const prompts_1 = tslib_1.__importDefault(require("prompts"));
15
15
  const execOptions = {
16
16
  encoding: 'utf8',
17
- stdio: [
18
- 'pipe',
19
- 'pipe',
20
- 'ignore',
21
- ],
17
+ stdio: [/* stdin */ 'pipe', /* stdout */ 'pipe', /* stderr */ 'ignore'],
22
18
  };
23
- // Clears console
24
19
  function clearConsole() {
25
20
  process.stdout.write(process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H');
26
21
  }
27
- // Gets process id of what is on port
28
- function getProcessIdOnPort(port) {
29
- return (0, child_process_1.execSync)(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
30
- .split('\n')[0]
31
- .trim();
32
- }
33
- // Gets process command
34
- function getProcessCommand(processId) {
35
- const command = (0, child_process_1.execSync)(`ps -o command -p ${processId} | sed -n 2p`, execOptions);
36
- return command.replace(/\n$/, '');
37
- }
38
- // Gets directory of a process from its process id
39
- function getDirectoryOfProcessById(processId) {
40
- return (0, child_process_1.execSync)(`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions).trim();
41
- }
42
- // Gets process on port
43
22
  function getProcessForPort(port) {
44
23
  try {
45
- const processId = getProcessIdOnPort(port);
46
- const directory = getDirectoryOfProcessById(processId);
47
- const command = getProcessCommand(processId);
24
+ const processId = (0, child_process_1.execSync)(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
25
+ .split('\n')[0]
26
+ .trim();
27
+ const directory = (0, child_process_1.execSync)(`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions).trim();
28
+ const command = (0, child_process_1.execSync)(`ps -o command -p ${processId} | sed -n 2p`, execOptions).replace(/\n$/, '');
48
29
  return logger_1.default.interpolate `code=${command} subdue=${`(pid ${processId})`} in path=${directory}`;
49
30
  }
50
31
  catch {
@@ -99,8 +99,8 @@ export default ${JSON.stringify(siteConfig, null, 2)};
99
99
  `);
100
100
  const genClientModules = (0, utils_1.generate)(generatedFilesDir, 'client-modules.js', `export default [
101
101
  ${clientModules
102
- // import() is async so we use require() because client modules can have
103
- // CSS and the order matters for loading CSS.
102
+ // Use `require()` because `import()` is async but client modules can have CSS
103
+ // and the order matters for loading CSS.
104
104
  .map((clientModule) => ` require('${(0, utils_1.escapePath)(clientModule)}'),`)
105
105
  .join('\n')}
106
106
  ];
@@ -67,7 +67,7 @@ async function loadPlugins(context) {
67
67
  return;
68
68
  }
69
69
  const pluginId = plugin.options.id;
70
- // plugins data files are namespaced by pluginName/pluginId
70
+ // Plugins data files are namespaced by pluginName/pluginId
71
71
  const dataDir = path_1.default.join(context.generatedFilesDir, plugin.name, pluginId);
72
72
  const pluginRouteContextModulePath = path_1.default.join(dataDir, `${(0, utils_1.docuHash)('pluginRouteContextModule')}.json`);
73
73
  const pluginRouteContext = {
@@ -17,7 +17,7 @@ const utils_validation_1 = require("@docusaurus/utils-validation");
17
17
  const configs_1 = require("./configs");
18
18
  function getOptionValidationFunction(normalizedPluginConfig) {
19
19
  if (normalizedPluginConfig.pluginModule) {
20
- // support both commonjs and ES modules
20
+ // Support both CommonJS and ES modules
21
21
  return (normalizedPluginConfig.pluginModule.module?.default?.validateOptions ??
22
22
  normalizedPluginConfig.pluginModule.module?.validateOptions);
23
23
  }
@@ -25,7 +25,7 @@ function getOptionValidationFunction(normalizedPluginConfig) {
25
25
  }
26
26
  function getThemeValidationFunction(normalizedPluginConfig) {
27
27
  if (normalizedPluginConfig.pluginModule) {
28
- // support both commonjs and ES modules
28
+ // Support both CommonJS and ES modules
29
29
  return (normalizedPluginConfig.pluginModule.module.default?.validateThemeConfig ??
30
30
  normalizedPluginConfig.pluginModule.module.validateThemeConfig);
31
31
  }
@@ -41,7 +41,6 @@ async function initPlugins(context) {
41
41
  const pluginRequire = (0, module_1.createRequire)(context.siteConfigPath);
42
42
  const pluginConfigs = await (0, configs_1.loadPluginConfigs)(context);
43
43
  async function doGetPluginVersion(normalizedPluginConfig) {
44
- // get plugin version
45
44
  if (normalizedPluginConfig.pluginModule?.path) {
46
45
  const pluginPath = pluginRequire.resolve(normalizedPluginConfig.pluginModule?.path);
47
46
  return (0, siteMetadata_1.getPluginVersion)(pluginPath, context.siteDir);
@@ -55,7 +55,7 @@ function mergeTranslationFileContent({ existingContent = {}, newContent, options
55
55
  message: options.override
56
56
  ? message
57
57
  : existingContent[key]?.message ?? message,
58
- description, // description
58
+ description,
59
59
  };
60
60
  });
61
61
  return result;
@@ -79,7 +79,7 @@ Maybe you should remove them? ${unknownKeys}`;
79
79
  await fs_extra_1.default.outputFile(filePath, `${JSON.stringify(mergedContent, null, 2)}\n`);
80
80
  }
81
81
  }
82
- // should we make this configurable?
82
+ // Should we make this configurable?
83
83
  function getTranslationsLocaleDirPath(context) {
84
84
  return path_1.default.join(context.siteDir, utils_1.I18N_DIR_NAME, context.locale);
85
85
  }
@@ -141,7 +141,7 @@ async function localizePluginTranslationFile({ siteDir, plugin, locale, translat
141
141
  });
142
142
  const localizedContent = await readTranslationFileContent(filePath);
143
143
  if (localizedContent) {
144
- // localized messages "override" default unlocalized messages
144
+ // Localized messages "override" default unlocalized messages
145
145
  return {
146
146
  path: translationFile.path,
147
147
  content: {
@@ -18,11 +18,11 @@ const CSS_REGEX = /\.css$/i;
18
18
  const CSS_MODULE_REGEX = /\.module\.css$/i;
19
19
  exports.clientDir = path_1.default.join(__dirname, '..', 'client');
20
20
  const LibrariesToTranspile = [
21
- 'copy-text-to-clipboard', // contains optional catch binding, incompatible with recent versions of Edge
21
+ 'copy-text-to-clipboard', // Contains optional catch binding, incompatible with recent versions of Edge
22
22
  ];
23
23
  const LibrariesToTranspileRegex = new RegExp(LibrariesToTranspile.map((libName) => `(node_modules/${libName})`).join('|'));
24
24
  function excludeJS(modulePath) {
25
- // always transpile client dir
25
+ // Always transpile client dir
26
26
  if (modulePath.startsWith(exports.clientDir)) {
27
27
  return false;
28
28
  }
@@ -135,7 +135,7 @@ async function createBaseConfig(props, isServer, minify = true) {
135
135
  // include [name] in the filenames
136
136
  name: false,
137
137
  cacheGroups: {
138
- // disable the built-in cacheGroups
138
+ // Disable the built-in cacheGroups
139
139
  default: false,
140
140
  common: {
141
141
  name: 'common',
@@ -206,7 +206,7 @@ async function createBaseConfig(props, isServer, minify = true) {
206
206
  chunkFilename: isProd
207
207
  ? 'assets/css/[name].[contenthash:8].css'
208
208
  : '[name].css',
209
- // remove css order warnings if css imports are not sorted
209
+ // Remove css order warnings if css imports are not sorted
210
210
  // alphabetically. See https://github.com/webpack-contrib/mini-css-extract-plugin/pull/422
211
211
  // for more reasoning
212
212
  ignoreOrder: true,
@@ -17,7 +17,7 @@ async function createClientConfig(props, minify = true) {
17
17
  const isBuilding = process.argv[2] === 'build';
18
18
  const config = await (0, base_1.createBaseConfig)(props, false, minify);
19
19
  const clientConfig = (0, webpack_merge_1.default)(config, {
20
- // useless, disabled on purpose (errors on existing sites with no
20
+ // Useless, disabled on purpose (errors on existing sites with no
21
21
  // browserslist config)
22
22
  // target: 'browserslist',
23
23
  entry: path_1.default.resolve(__dirname, '../client/clientEntry.js'),
@@ -143,7 +143,7 @@ function applyConfigureWebpack(configureWebpack, config, isServer, jsLoader, con
143
143
  }
144
144
  exports.applyConfigureWebpack = applyConfigureWebpack;
145
145
  function applyConfigurePostCss(configurePostCss, config) {
146
- // not ideal heuristic but good enough for our use-case?
146
+ // Not ideal heuristic but good enough for our use-case?
147
147
  function isPostCssLoader(loader) {
148
148
  return !!loader?.options?.postcssOptions;
149
149
  }
@@ -176,7 +176,7 @@ function compile(config) {
176
176
  }
177
177
  reject(err);
178
178
  }
179
- // let plugins consume all the stats
179
+ // Let plugins consume all the stats
180
180
  const errorsWarnings = stats?.toJson('errors-warnings');
181
181
  if (stats?.hasErrors()) {
182
182
  reject(new Error('Failed to compile with errors.'));
@@ -266,7 +266,7 @@ function getMinimizer(useSimpleCssMinifier = false) {
266
266
  parallel: getTerserParallel(),
267
267
  terserOptions: {
268
268
  parse: {
269
- // we want uglify-js to parse ecma 8 code. However, we don't want it
269
+ // We want uglify-js to parse ecma 8 code. However, we don't want it
270
270
  // to apply any minification steps that turns valid ecma 5 code
271
271
  // into invalid ecma 5 code. This is why the 'compress' and 'output'
272
272
  // sections only apply transformations that are ecma 5 safe
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@docusaurus/core",
3
3
  "description": "Easy to Maintain Open Source Documentation Websites",
4
- "version": "0.0.0-4875",
4
+ "version": "0.0.0-4879",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -41,13 +41,13 @@
41
41
  "@babel/runtime": "^7.17.9",
42
42
  "@babel/runtime-corejs3": "^7.17.9",
43
43
  "@babel/traverse": "^7.17.9",
44
- "@docusaurus/cssnano-preset": "0.0.0-4875",
45
- "@docusaurus/logger": "0.0.0-4875",
46
- "@docusaurus/mdx-loader": "0.0.0-4875",
44
+ "@docusaurus/cssnano-preset": "0.0.0-4879",
45
+ "@docusaurus/logger": "0.0.0-4879",
46
+ "@docusaurus/mdx-loader": "0.0.0-4879",
47
47
  "@docusaurus/react-loadable": "5.5.2",
48
- "@docusaurus/utils": "0.0.0-4875",
49
- "@docusaurus/utils-common": "0.0.0-4875",
50
- "@docusaurus/utils-validation": "0.0.0-4875",
48
+ "@docusaurus/utils": "0.0.0-4879",
49
+ "@docusaurus/utils-common": "0.0.0-4879",
50
+ "@docusaurus/utils-validation": "0.0.0-4879",
51
51
  "@slorber/static-site-generator-webpack-plugin": "^4.0.4",
52
52
  "@svgr/webpack": "^6.2.1",
53
53
  "autoprefixer": "^10.4.4",
@@ -56,11 +56,11 @@
56
56
  "boxen": "^6.2.1",
57
57
  "chokidar": "^3.5.3",
58
58
  "clean-css": "^5.3.0",
59
- "cli-table3": "^0.6.1",
59
+ "cli-table3": "^0.6.2",
60
60
  "combine-promises": "^1.1.0",
61
61
  "commander": "^5.1.0",
62
62
  "copy-webpack-plugin": "^10.2.4",
63
- "core-js": "^3.21.1",
63
+ "core-js": "^3.22.0",
64
64
  "css-loader": "^6.7.1",
65
65
  "css-minimizer-webpack-plugin": "^3.4.1",
66
66
  "cssnano": "^5.1.7",
@@ -69,7 +69,7 @@
69
69
  "escape-html": "^1.0.3",
70
70
  "eta": "^1.12.3",
71
71
  "file-loader": "^6.2.0",
72
- "fs-extra": "^10.0.1",
72
+ "fs-extra": "^10.1.0",
73
73
  "html-minifier-terser": "^6.1.0",
74
74
  "html-tags": "^3.2.0",
75
75
  "html-webpack-plugin": "^5.5.0",
@@ -81,8 +81,8 @@
81
81
  "postcss": "^8.4.12",
82
82
  "postcss-loader": "^6.2.1",
83
83
  "prompts": "^2.4.2",
84
- "react-dev-utils": "^12.0.0",
85
- "react-helmet-async": "^1.2.3",
84
+ "react-dev-utils": "^12.0.1",
85
+ "react-helmet-async": "^1.3.0",
86
86
  "react-loadable": "npm:@docusaurus/react-loadable@5.5.2",
87
87
  "react-loadable-ssr-addon-v5-slorber": "^1.0.1",
88
88
  "react-router": "^5.2.0",
@@ -90,7 +90,7 @@
90
90
  "react-router-dom": "^5.2.0",
91
91
  "remark-admonitions": "^1.2.1",
92
92
  "rtl-detect": "^1.0.4",
93
- "semver": "^7.3.6",
93
+ "semver": "^7.3.7",
94
94
  "serve-handler": "^6.1.3",
95
95
  "shelljs": "^0.8.5",
96
96
  "terser-webpack-plugin": "^5.3.1",
@@ -105,11 +105,11 @@
105
105
  "webpackbar": "^5.0.2"
106
106
  },
107
107
  "devDependencies": {
108
- "@docusaurus/module-type-aliases": "0.0.0-4875",
109
- "@docusaurus/types": "0.0.0-4875",
108
+ "@docusaurus/module-type-aliases": "0.0.0-4879",
109
+ "@docusaurus/types": "0.0.0-4879",
110
110
  "@types/detect-port": "^1.3.2",
111
111
  "@types/nprogress": "^0.2.0",
112
- "@types/react-dom": "^18.0.0",
112
+ "@types/react-dom": "^18.0.1",
113
113
  "@types/react-router-config": "^5.0.6",
114
114
  "@types/rtl-detect": "^1.0.0",
115
115
  "@types/serve-handler": "^6.1.1",
@@ -127,5 +127,5 @@
127
127
  "engines": {
128
128
  "node": ">=14"
129
129
  },
130
- "gitHead": "ee48d072632c7eb6d03da4acf5800f8d42eee680"
130
+ "gitHead": "0ebf7473396171d10b7c91bc3f33cdf16863ee5c"
131
131
  }