watskeburt 0.11.6 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -24,26 +24,20 @@ but for just this simple usage they're a bit overkill.
24
24
  ### :scroll: API
25
25
 
26
26
  ```javascript
27
- // const { listSync, getSHASync } = require("watskeburt"); // in commonjs contexts you can also require it
28
- import { list, getSHA, listSync, getSHASync } from "watskeburt";
27
+ import { list, getSHA } from "watskeburt";
29
28
 
30
29
  // print the SHA1 of the current HEAD
31
30
  console.log(await getSHA());
32
- console.log(getSHASync());
33
31
 
34
32
  // list all files that differ between 'main' and the current revision (including
35
33
  // files not staged for commit and files not under revision control)
36
34
  /** @type {import('watskeburt').IChange[]} */
37
35
  const lChangedFiles = await list("main");
38
- // or with the synchronous interface:
39
- // const lChangedFiles = listSync("main");
40
36
 
41
37
  // list all files that differ between 'v0.6.1' and 'v0.7.1' (by definition
42
38
  // won't include files staged for commit and/ or not under revision control)
43
39
  /** @type {import('watskeburt').IChange[]} */
44
40
  const lChangedFiles = await list("v0.6.1", "v0.7.1");
45
- // or with the synchronous interface:
46
- // const lChangedFiles = listSync("v0.6.1", "v0.7.1");
47
41
 
48
42
  // As a third parameter you can pass some options
49
43
  // (pass null as the second parameter if you only want to compare between
@@ -53,11 +47,6 @@ const lChangedFiles = await list("main", null, {
53
47
  trackedOnly: false, // when set to true leaves out files not under revision control
54
48
  outputType: "object", // other options: "json" and "regex" (as used in the CLI)
55
49
  });
56
- // or with the synchronous interface:
57
- // const lChangedFiles = listSync("main", null, {
58
- // trackedOnly: false, // when set to true leaves out files not under revision control
59
- // outputType: "object", // other options: "json" and "regex" (as used in the CLI)
60
- // });
61
50
  ```
62
51
 
63
52
  The array of changes this returns looks like this:
package/dist/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { cli } from "./execute-cli.js";
3
+ await cli();
@@ -13,7 +13,7 @@ Options:
13
13
  --trackedOnly only take tracked files into account (default: false)
14
14
  -V, --version output the version number
15
15
  -h, --help display help for command${EOL}`;
16
- export async function cli(pArguments = process.argv.slice(2), pOutStream = process.stdout, pErrorStream = process.stderr) {
16
+ export async function cli(pArguments = process.argv.slice(2), pOutStream = process.stdout, pErrorStream = process.stderr, pErrorExitCode = 1) {
17
17
  try {
18
18
  const lArguments = getArguments(pArguments);
19
19
  if (lArguments.values.help) {
@@ -26,7 +26,7 @@ export async function cli(pArguments = process.argv.slice(2), pOutStream = proce
26
26
  }
27
27
  if (!outputTypeIsValid(lArguments.values.outputType)) {
28
28
  pErrorStream.write(`error: option '-T, --outputType <type>' argument '${lArguments.values.outputType}' is invalid. Allowed choices are json, regex.${EOL}`);
29
- process.exitCode = 1;
29
+ process.exitCode = pErrorExitCode;
30
30
  return;
31
31
  }
32
32
  const lResult = await list(lArguments.positionals[0], lArguments.positionals[1], lArguments.values);
@@ -34,7 +34,7 @@ export async function cli(pArguments = process.argv.slice(2), pOutStream = proce
34
34
  }
35
35
  catch (pError) {
36
36
  pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
37
- process.exitCode = 1;
37
+ process.exitCode = pErrorExitCode;
38
38
  }
39
39
  }
40
40
  function getArguments(pArguments) {
@@ -1,5 +1,4 @@
1
1
  import { convertDiffLines, convertStatusLines, } from "./convert-to-change-object.js";
2
- import * as primitivesSync from "./git-primitives-sync.js";
3
2
  import * as primitives from "./git-primitives.js";
4
3
  import format from "./formatters/format.js";
5
4
  export async function list(pOldRevision, pNewRevision, pOptions) {
@@ -15,18 +14,6 @@ export async function list(pOldRevision, pNewRevision, pOptions) {
15
14
  }
16
15
  return format(lChanges, lOptions.outputType);
17
16
  }
18
- export function listSync(pOldRevision, pNewRevision, pOptions) {
19
- const lOldRevision = pOldRevision || primitivesSync.getSHASync();
20
- const lOptions = pOptions || {};
21
- let lChanges = convertDiffLines(primitivesSync.getDiffLinesSync(lOldRevision, pNewRevision));
22
- if (!lOptions.trackedOnly) {
23
- lChanges = lChanges.concat(convertStatusLines(primitivesSync.getStatusShortSync()).filter(({ changeType }) => changeType === "untracked"));
24
- }
25
- return format(lChanges, lOptions.outputType);
26
- }
27
17
  export function getSHA() {
28
18
  return primitives.getSHA();
29
19
  }
30
- export function getSHASync() {
31
- return primitivesSync.getSHASync();
32
- }
@@ -0,0 +1 @@
1
+ export const VERSION = "0.12.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watskeburt",
3
- "version": "0.11.6",
3
+ "version": "0.12.1",
4
4
  "description": "List files changed since a git revision",
5
5
  "keywords": [
6
6
  "git",
@@ -19,23 +19,21 @@
19
19
  "url": "https://sverweij.github.io"
20
20
  },
21
21
  "license": "MIT",
22
- "bin": "bin/cli.js",
23
- "main": "dist/cjs-bundle.cjs",
24
- "module": "dist/esm/main.js",
22
+ "bin": "dist/cli.js",
23
+ "main": "dist/main.js",
24
+ "module": "dist/main.js",
25
25
  "type": "module",
26
26
  "sideEffects": false,
27
27
  "exports": {
28
28
  ".": [
29
29
  {
30
- "import": "./dist/esm/main.js",
31
- "require": "./dist/cjs-bundle.cjs"
30
+ "import": "./dist/main.js"
32
31
  },
33
- "./dist/cjs-bundle.cjs"
32
+ "./dist/main.js"
34
33
  ]
35
34
  },
36
35
  "types": "types/watskeburt.d.ts",
37
36
  "files": [
38
- "bin",
39
37
  "dist",
40
38
  "!**/*.DS_Store",
41
39
  "types",
@@ -44,23 +42,20 @@
44
42
  "README.md"
45
43
  ],
46
44
  "devDependencies": {
47
- "@types/mocha": "10.0.1",
48
- "@types/node": "20.4.1",
49
- "@typescript-eslint/eslint-plugin": "6.0.0",
50
- "c8": "8.0.0",
51
- "dependency-cruiser": "13.1.0",
52
- "esbuild": "0.18.11",
53
- "eslint": "8.44.0",
45
+ "@types/node": "20.4.5",
46
+ "@typescript-eslint/eslint-plugin": "6.2.1",
47
+ "c8": "8.0.1",
48
+ "dependency-cruiser": "13.1.1",
49
+ "eslint": "8.46.0",
54
50
  "eslint-config-moving-meadow": "4.0.2",
55
- "eslint-config-prettier": "8.8.0",
51
+ "eslint-config-prettier": "8.9.0",
56
52
  "eslint-plugin-budapestian": "5.0.1",
57
53
  "eslint-plugin-eslint-comments": "3.2.0",
58
- "eslint-plugin-import": "2.27.5",
54
+ "eslint-plugin-import": "2.28.0",
59
55
  "eslint-plugin-mocha": "10.1.0",
60
56
  "eslint-plugin-node": "11.1.0",
61
57
  "eslint-plugin-security": "1.7.1",
62
- "eslint-plugin-unicorn": "47.0.0",
63
- "mocha": "10.2.0",
58
+ "eslint-plugin-unicorn": "48.0.1",
64
59
  "npm-run-all": "4.1.5",
65
60
  "prettier": "3.0.0",
66
61
  "ts-node": "10.9.1",
@@ -74,29 +69,28 @@
74
69
  "build": "npm-run-all --sequential build:clean build:version build:dist",
75
70
  "build:version": "node --no-warnings --loader ts-node/esm tools/get-version.ts > src/version.ts",
76
71
  "build:clean": "rm -rf dist/*",
77
- "build:dist": "npm-run-all build:dist:*",
78
- "build:dist:cjs": "esbuild src/main.ts --format=cjs --target=node14 --platform=node --bundle --global-name=wkbtcjs --minify --outfile=dist/cjs-bundle.cjs",
79
- "build:dist:esm": "tsc",
72
+ "build:dist": "tsc",
80
73
  "check": "npm-run-all --parallel --aggregate-output lint depcruise test:cover",
81
74
  "clean": "rm -rf dist",
82
- "test": "NODE_OPTIONS=--no-warnings mocha",
83
- "test:cover": "NODE_OPTIONS=--no-warnings c8 mocha",
84
- "depcruise": "depcruise bin dist src types",
85
- "depcruise:graph": "depcruise bin src types --include-only '^(bin|dist|src|types)' --output-type dot | dot -T svg | tee docs/dependency-graph.svg | depcruise-wrap-stream-in-html > docs/dependency-graph.html",
86
- "depcruise:graph:archi": "depcruise bin src --include-only '^(bin|dist|src|types)' --output-type archi | dot -T svg | depcruise-wrap-stream-in-html > docs/high-level-dependency-graph.html",
87
- "depcruise:graph:dev": "depcruise bin dist src types --include-only '^(bin|dist|src|types)' --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
88
- "depcruise:graph:diff:dev": "depcruise bin dist src types --include-only '^(bin|dist|src|types)' --highlight \"$(node bin/cli.js main -T regex)\" --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
89
- "depcruise:graph:diff:mermaid": "depcruise bin dist src types --include-only '^(bin|dist|src|types)' --output-type mermaid --output-to - --highlight \"$(node bin/cli.js $SHA -T regex)\"",
90
- "depcruise:html": "depcruise bin src types --progress --output-type err-html --output-to dependency-violation-report.html",
91
- "depcruise:text": "depcruise bin src types --progress --output-type text",
92
- "depcruise:focus": "depcruise bin src types --progress --output-type text --focus",
93
- "depcruise:reaches": "depcruise bin src types --progress --output-type text --reaches",
94
- "format": "prettier --write \"{bin,src,tools}/**/*.{js,ts}\" \"types/**/*.ts\" \"*.{json,yml,md,js}\"",
95
- "format:check": "prettier --loglevel warn --check \"{bin,src,tools}/**/*.ts\" \"types/**/*.ts\" \"*.{json,yml,md,js}\"",
75
+ "test": "node --no-warnings --loader 'ts-node/esm' --test-reporter dot --test src/*.spec.ts src/**/*.spec.ts",
76
+ "test:cover": "c8 npm test",
77
+ "test:only-for-node-16-without-the-test-reporter": "node --no-warnings --loader 'ts-node/esm' --test src/*.spec.ts src/**/*.spec.ts",
78
+ "depcruise": "depcruise dist src types",
79
+ "depcruise:graph": "depcruise src types --include-only '^(dist|src|types)' --output-type dot | dot -T svg | tee docs/dependency-graph.svg | depcruise-wrap-stream-in-html > docs/dependency-graph.html",
80
+ "depcruise:graph:archi": "depcruise src --include-only '^(dist|src|types)' --output-type archi | dot -T svg | depcruise-wrap-stream-in-html > docs/high-level-dependency-graph.html",
81
+ "depcruise:graph:dev": "depcruise dist src types --include-only '^(dist|src|types)' --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
82
+ "depcruise:graph:diff:dev": "depcruise dist src types --include-only '^(dist|src|types)' --highlight \"$(node dist/cli.js main -T regex)\" --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
83
+ "depcruise:graph:diff:mermaid": "depcruise dist src types --include-only '^(dist|src|types)' --output-type mermaid --output-to - --highlight \"$(node dist/cli.js $SHA -T regex)\"",
84
+ "depcruise:html": "depcruise src types --progress --output-type err-html --output-to dependency-violation-report.html",
85
+ "depcruise:text": "depcruise src types --progress --output-type text",
86
+ "depcruise:focus": "depcruise src types --progress --output-type text --focus",
87
+ "depcruise:reaches": "depcruise src types --progress --output-type text --reaches",
88
+ "format": "prettier --write \"{src,tools}/**/*.{js,ts}\" \"types/**/*.ts\" \"*.{json,yml,md,js}\"",
89
+ "format:check": "prettier --log-level warn --check \"{src,tools}/**/*.ts\" \"types/**/*.ts\" \"*.{json,yml,md,js}\"",
96
90
  "lint": "npm-run-all --parallel --aggregate-output format:check lint:eslint lint:types",
97
91
  "lint:fix": "npm-run-all --parallel --aggregate-output format lint:eslint:fix",
98
- "lint:eslint": "eslint bin src types tools --cache --cache-location node_modules/.cache/eslint/",
99
- "lint:eslint:fix": "eslint bin src types tools --fix --cache --cache-location node_modules/.cache/eslint/",
92
+ "lint:eslint": "eslint src types tools --cache --cache-location node_modules/.cache/eslint/",
93
+ "lint:eslint:fix": "eslint src types tools --fix --cache --cache-location node_modules/.cache/eslint/",
100
94
  "lint:types": "tsc --noEmit",
101
95
  "scm:stage": "git add .",
102
96
  "update-dependencies": "run-s upem:update upem:install lint:fix check",
@@ -61,43 +61,6 @@ export interface IInternalOptions {
61
61
 
62
62
  export type IOptions = IFormatOptions | IInternalOptions;
63
63
 
64
- /**
65
- * returns a list of files changed since pOldRevision.
66
- *
67
- * @param pOldRevision The revision against which to compare. E.g. a commit-hash,
68
- * a branch or a tag. When not passed defaults to the _current_
69
- * commit hash (if there's any)
70
- * @param pNewRevision Newer revision against which to compare. Leave out or pass
71
- * null when you want to compare against the working tree
72
- * @param pOptions Options that influence how the changes are returned and that
73
- * filter what is returned and
74
- * @throws {Error}
75
- */
76
- export function listSync(
77
- pOldRevision?: string,
78
- pNewRevision?: string,
79
- pOptions?: IInternalOptions,
80
- ): IChange[];
81
-
82
- /**
83
- * returns a list of files changed since pOldRevision formatted into a string
84
- * as pOptions.outputType
85
- *
86
- * @param pOldRevision The revision against which to compare. E.g. a commit-hash,
87
- * a branch or a tag. When not passed defaults to the _current_
88
- * commit hash (if there's any)
89
- * @param pNewRevision Newer revision against which to compare. Leave out or pass
90
- * null when you want to compare against the working tree
91
- * @param pOptions Options that influence how the changes are returned and that
92
- * filter what is returned and
93
- * @throws {Error}
94
- */
95
- export function listSync(
96
- pOldRevision?: string,
97
- pNewRevision?: string,
98
- pOptions?: IFormatOptions,
99
- ): string;
100
-
101
64
  /**
102
65
  * returns promise of a list of files changed since pOldRevision.
103
66
  *
@@ -135,13 +98,6 @@ export function list(
135
98
  pOptions?: IFormatOptions,
136
99
  ): Promise<string>;
137
100
 
138
- /**
139
- * Returns the SHA1 of the current HEAD
140
- *
141
- * @throws {Error}
142
- */
143
- export function getSHASync(): string;
144
-
145
101
  /**
146
102
  * Returns the SHA1 of the current HEAD
147
103
  *
package/bin/cli.js DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { cli } from "../dist/esm/cli.js";
4
-
5
- await cli();
@@ -1 +0,0 @@
1
- "use strict";var l=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var k=(e,t)=>{for(var n in t)l(e,n,{get:t[n],enumerable:!0})},H=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of v(t))!_.call(e,s)&&s!==n&&l(e,s,{get:()=>t[s],enumerable:!(r=$(t,s))||r.enumerable});return e};var b=e=>H(l({},"__esModule",{value:!0}),e);var ee={};k(ee,{getSHA:()=>W,getSHASync:()=>Z,list:()=>K,listSync:()=>Q});module.exports=b(ee);var y=require("os"),B=/^(?<changeType>[ACDMRTUXB])(?<similarity>[0-9]{3})?[ \t]+(?<name>[^ \t]+)[ \t]*(?<newName>[^ \t]+)?$/,U=/^(?<stagedChangeType>[ ACDMRTUXB?!])(?<unStagedChangeType>[ ACDMRTUXB?!])[ \t]+(?<name>[^ \t]+)(( -> )(?<newName>[^ \t]+))?$/,j=new Map([["A","added"],["C","copied"],["D","deleted"],["M","modified"],["R","renamed"],["T","type changed"],["U","unmerged"],["B","pairing broken"],[" ","unmodified"],["?","untracked"],["!","ignored"]]);function d(e){return e.split(y.EOL).filter(Boolean).map(R).filter(({name:t,changeType:n})=>!!t&&!!n)}function R(e){let t=e.match(U),n={};if(t!=null&&t.groups){let r=m(t.groups.stagedChangeType),s=m(t.groups.unStagedChangeType);n.changeType=r==="unmodified"?s:r,t.groups.newName?(n.name=t.groups.newName,n.oldName=t.groups.name):n.name=t.groups.name}return n}function T(e){return e.split(y.EOL).filter(Boolean).map(F).filter(({name:t,changeType:n})=>!!t&&!!n)}function F(e){let t=e.match(B),n={};return t!=null&&t.groups&&(n.changeType=m(t.groups.changeType),t.groups.newName?(n.name=t.groups.newName,n.oldName=t.groups.name):n.name=t.groups.name),n}function m(e){return j.get(e)??"unknown"}var c=require("child_process");function A(e=c.spawnSync){let t=new Map([[129,`'${process.cwd()}' does not seem to be a git repository`]]);return h(["status","--porcelain"],t,e)}function N(e,t,n=c.spawnSync){let r=new Map([[128,`revision '${e}' ${t?`(or '${t}') `:""}unknown`],[129,`'${process.cwd()}' does not seem to be a git repository`]]);return h(t?["diff",e,t,"--name-status"]:["diff",e,"--name-status"],r,n)}function S(e=c.spawnSync){return h(["rev-parse","HEAD"],new Map,e).slice(0,40)}function h(e,t,n){let r=n("git",e,{cwd:process.cwd(),env:process.env});if(r.error&&G(r.error),r.status===0)return M(r.stdout);throw new Error(t.get(r.status??0)||`internal git error: ${r.status} (${M(r.stderr)})`)}function M(e){return e instanceof Buffer?e.toString("utf8"):e}function G(e){throw e.code==="ENOENT"?new Error("git executable not found"):new Error(`internal spawn error: ${e}`)}var u=require("child_process");async function L(e=u.spawn){let t=new Map([[129,`'${process.cwd()}' does not seem to be a git repository`]]);return await C(["status","--porcelain"],t,e)}async function O(e,t,n=u.spawn){let r=new Map([[128,`revision '${e}' ${t?`(or '${t}') `:""}unknown`],[129,`'${process.cwd()}' does not seem to be a git repository`]]);return await C(t?["diff",e,t,"--name-status"]:["diff",e,"--name-status"],r,n)}async function w(e=u.spawn){return(await C(["rev-parse","HEAD"],new Map,e)).slice(0,40)}function C(e,t,n){let r=n("git",e,{cwd:process.cwd(),env:process.env}),s="",a="";return new Promise((p,i)=>{var g,x;(g=r.stdout)==null||g.on("data",o=>{s=s.concat(o)}),(x=r.stderr)==null||x.on("data",o=>{a=a.concat(o)}),r.on("close",o=>{o===0?p(D(s)):i(new Error(t.get(o??0)||`internal git error: ${o} (${D(a)})`))}),r.on("error",o=>{(o==null?void 0:o.code)==="ENOENT"?i(new Error("git executable not found")):i(new Error(`internal spawn error: ${o}`))})})}function D(e){return e instanceof Buffer?e.toString("utf8"):e}var P=require("path"),Y=new Set([".cjs",".cjsx",".coffee",".csx",".cts",".js",".json",".jsx",".litcoffee",".ls",".mjs",".mts",".svelte",".ts",".tsx",".vue",".vuex"]),V=new Set(["modified","added","renamed","copied","untracked"]);function I(e,t=Y,n=V){return`^(${e.filter(s=>n.has(s.changeType)).map(({name:s})=>s).filter(s=>t.has((0,P.extname)(s))).map(s=>s.replace(/\\/g,"\\\\").replace(/\./g,"\\.")).join("|")})$`}function E(e){return JSON.stringify(e,null,2)}var q=e=>e,z=new Map([["regex",I],["json",E]]);function f(e,t){return(z.get(t??"unknown")||q)(e)}async function K(e,t,n){let r=e||await w(),s=n||{},[a,p]=await Promise.all([O(r,t),s.trackedOnly?"":L()]),i=T(a);return s.trackedOnly||(i=i.concat(d(p).filter(({changeType:g})=>g==="untracked"))),f(i,s.outputType)}function Q(e,t,n){let r=e||S(),s=n||{},a=T(N(r,t));return s.trackedOnly||(a=a.concat(d(A()).filter(({changeType:p})=>p==="untracked"))),f(a,s.outputType)}function W(){return w()}function Z(){return S()}0&&(module.exports={getSHA,getSHASync,list,listSync});
@@ -1,55 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- export function getStatusShortSync(pSpawnFunction = spawnSync) {
3
- const lErrorMap = new Map([
4
- [129, `'${process.cwd()}' does not seem to be a git repository`],
5
- ]);
6
- return getGitResultSync(["status", "--porcelain"], lErrorMap, pSpawnFunction);
7
- }
8
- export function getDiffLinesSync(pOldRevision, pNewRevision, pSpawnFunction = spawnSync) {
9
- const lErrorMap = new Map([
10
- [
11
- 128,
12
- `revision '${pOldRevision}' ${pNewRevision ? `(or '${pNewRevision}') ` : ""}unknown`,
13
- ],
14
- [129, `'${process.cwd()}' does not seem to be a git repository`],
15
- ]);
16
- return getGitResultSync(pNewRevision
17
- ? ["diff", pOldRevision, pNewRevision, "--name-status"]
18
- : ["diff", pOldRevision, "--name-status"], lErrorMap, pSpawnFunction);
19
- }
20
- export function getSHASync(pSpawnFunction = spawnSync) {
21
- const lSha1Length = 40;
22
- return getGitResultSync(["rev-parse", "HEAD"], new Map(), pSpawnFunction).slice(0, lSha1Length);
23
- }
24
- function getGitResultSync(pArguments, pErrorMap, pSpawnFunction) {
25
- const lGitResult = pSpawnFunction("git", pArguments, {
26
- cwd: process.cwd(),
27
- env: process.env,
28
- });
29
- if (lGitResult.error) {
30
- throwSpawnError(lGitResult.error);
31
- }
32
- if (lGitResult.status === 0) {
33
- return stringifyOutStream(lGitResult.stdout);
34
- }
35
- else {
36
- throw new Error(pErrorMap.get(lGitResult.status ?? 0) ||
37
- `internal git error: ${lGitResult.status} (${stringifyOutStream(lGitResult.stderr)})`);
38
- }
39
- }
40
- function stringifyOutStream(pError) {
41
- if (pError instanceof Buffer) {
42
- return pError.toString("utf8");
43
- }
44
- else {
45
- return pError;
46
- }
47
- }
48
- function throwSpawnError(pError) {
49
- if (pError.code === "ENOENT") {
50
- throw new Error("git executable not found");
51
- }
52
- else {
53
- throw new Error(`internal spawn error: ${pError}`);
54
- }
55
- }
@@ -1 +0,0 @@
1
- export const VERSION = "0.11.6";
File without changes
File without changes
File without changes