@esportsplus/routing 0.0.11 → 0.0.13
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/build/constants.d.ts +4 -0
- package/build/constants.js +4 -0
- package/build/index.d.ts +2 -2
- package/build/index.js +2 -2
- package/build/router/index.d.ts +1 -1
- package/build/router/index.js +7 -8
- package/build/router/node.js +1 -1
- package/build/spa.d.ts +17 -0
- package/build/spa.js +55 -0
- package/build/types.d.ts +7 -2
- package/package.json +5 -5
- package/src/index.ts +2 -2
- package/src/router/index.ts +12 -12
- package/src/router/node.ts +1 -1
- package/src/spa.ts +85 -0
- package/src/types.ts +7 -2
- package/tsconfig.json +1 -1
- package/src/hash.ts +0 -106
- /package/src/{symbols.ts → constants.ts} +0 -0
package/build/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import spa from './spa';
|
|
2
2
|
import middleware from './middleware';
|
|
3
3
|
import router from './router';
|
|
4
4
|
import slugify from './slugify';
|
|
5
|
-
export {
|
|
5
|
+
export { spa, middleware, router, slugify };
|
|
6
6
|
export * from './types';
|
package/build/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import spa from './spa';
|
|
2
2
|
import middleware from './middleware';
|
|
3
3
|
import router from './router';
|
|
4
4
|
import slugify from './slugify';
|
|
5
|
-
export {
|
|
5
|
+
export { spa, middleware, router, slugify };
|
|
6
6
|
export * from './types';
|
package/build/router/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ declare class Router {
|
|
|
16
16
|
routes: (fn: (router: Router) => void) => void;
|
|
17
17
|
};
|
|
18
18
|
match(method: string, path: string, subdomain?: string | null): ReturnType<Node['find']>;
|
|
19
|
-
on(methods: string[], options: Options):
|
|
19
|
+
on(methods: string[], options: Options): this;
|
|
20
20
|
post(options: Options): this;
|
|
21
21
|
put(options: Options): this;
|
|
22
22
|
uri(name: string, values?: unknown[]): string;
|
package/build/router/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATIC } from "../
|
|
1
|
+
import { STATIC } from "../constants";
|
|
2
2
|
import { Node } from './node';
|
|
3
3
|
import { normalize, radixkey } from './path';
|
|
4
4
|
import { Route } from './route';
|
|
@@ -31,13 +31,13 @@ class Router {
|
|
|
31
31
|
this.root = new Node();
|
|
32
32
|
}
|
|
33
33
|
add(radixkey, route) {
|
|
34
|
-
|
|
35
|
-
if (node.type === STATIC) {
|
|
34
|
+
if (radixkey.indexOf(':') === -1 || this.root.add(radixkey, route).type === STATIC) {
|
|
36
35
|
if (this.static[radixkey]) {
|
|
37
36
|
throw new Error(`Routing: static path '${radixkey}' is already in use`);
|
|
38
37
|
}
|
|
39
38
|
this.static[radixkey] = route;
|
|
40
39
|
}
|
|
40
|
+
return this;
|
|
41
41
|
}
|
|
42
42
|
route({ middleware, name, path, responder, subdomain }) {
|
|
43
43
|
let route = new Route(responder);
|
|
@@ -79,10 +79,8 @@ class Router {
|
|
|
79
79
|
}
|
|
80
80
|
match(method, path, subdomain) {
|
|
81
81
|
let key = radixkey(path, { method, subdomain });
|
|
82
|
-
if (this.static
|
|
83
|
-
return {
|
|
84
|
-
route: this.static[key]
|
|
85
|
-
};
|
|
82
|
+
if (key in this.static) {
|
|
83
|
+
return { route: this.static[key] };
|
|
86
84
|
}
|
|
87
85
|
return this.root.find(key);
|
|
88
86
|
}
|
|
@@ -119,6 +117,7 @@ class Router {
|
|
|
119
117
|
this.subdomains.push(route.subdomain);
|
|
120
118
|
}
|
|
121
119
|
}
|
|
120
|
+
return this;
|
|
122
121
|
}
|
|
123
122
|
post(options) {
|
|
124
123
|
this.on(['POST'], options);
|
|
@@ -129,7 +128,7 @@ class Router {
|
|
|
129
128
|
return this;
|
|
130
129
|
}
|
|
131
130
|
uri(name, values = []) {
|
|
132
|
-
let path = this.routes
|
|
131
|
+
let path = this.routes[name]?.path;
|
|
133
132
|
if (!path) {
|
|
134
133
|
throw new Error(`Routing: route name '${name}' does not exist or it does not provide a path`);
|
|
135
134
|
}
|
package/build/router/node.js
CHANGED
package/build/spa.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Request, Router } from './types';
|
|
2
|
+
type Cache = {
|
|
3
|
+
factory: typeof request;
|
|
4
|
+
state: Request;
|
|
5
|
+
};
|
|
6
|
+
declare const request: (url?: string) => Request;
|
|
7
|
+
declare const _default: (router: Router, state: Cache['state'], factory?: Cache['factory']) => {
|
|
8
|
+
back: () => void;
|
|
9
|
+
forward: () => void;
|
|
10
|
+
redirect: (path: string, { state, values }: {
|
|
11
|
+
state?: Record<PropertyKey, unknown> | undefined;
|
|
12
|
+
values?: unknown[] | undefined;
|
|
13
|
+
}) => void;
|
|
14
|
+
request: (url?: string) => Request;
|
|
15
|
+
uri: (path: string, values?: unknown[]) => string;
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
package/build/spa.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
let cache = [];
|
|
2
|
+
function update() {
|
|
3
|
+
for (let i = 0, n = cache.length; i < n; i++) {
|
|
4
|
+
let { factory, state } = cache[i], values = factory();
|
|
5
|
+
for (let key in values) {
|
|
6
|
+
state[key] = values[key];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const back = () => window.history.back();
|
|
11
|
+
const forward = () => window.history.forward();
|
|
12
|
+
const request = (url = window?.location?.href || '') => {
|
|
13
|
+
let { hash, hostname, href, origin, port, protocol } = new URL(url), path = hash?.replace('#/', '/')?.split('?') || ['/', ''];
|
|
14
|
+
return {
|
|
15
|
+
data: {},
|
|
16
|
+
href,
|
|
17
|
+
hostname,
|
|
18
|
+
method: 'GET',
|
|
19
|
+
origin,
|
|
20
|
+
path: path[0],
|
|
21
|
+
port,
|
|
22
|
+
protocol,
|
|
23
|
+
query: Object.fromEntries((new URLSearchParams(path[1])).entries())
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default (router, state, factory) => {
|
|
27
|
+
cache.push({
|
|
28
|
+
factory: factory || request,
|
|
29
|
+
state
|
|
30
|
+
});
|
|
31
|
+
update();
|
|
32
|
+
window.addEventListener('popstate', update);
|
|
33
|
+
return {
|
|
34
|
+
back,
|
|
35
|
+
forward,
|
|
36
|
+
redirect: (path, { state, values }) => {
|
|
37
|
+
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
38
|
+
return window.location.replace(path);
|
|
39
|
+
}
|
|
40
|
+
let uri = router.uri(path, values || []);
|
|
41
|
+
if (uri[0] === '/') {
|
|
42
|
+
uri = '#' + uri;
|
|
43
|
+
}
|
|
44
|
+
window.history.pushState(state || {}, '', uri);
|
|
45
|
+
},
|
|
46
|
+
request: factory || request,
|
|
47
|
+
uri: (path, values = []) => {
|
|
48
|
+
let uri = router.uri(path, values || []);
|
|
49
|
+
if (uri[0] === '/') {
|
|
50
|
+
uri = '#' + uri;
|
|
51
|
+
}
|
|
52
|
+
return uri;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
};
|
package/build/types.d.ts
CHANGED
|
@@ -8,11 +8,16 @@ type Options = {
|
|
|
8
8
|
subdomain?: string;
|
|
9
9
|
};
|
|
10
10
|
type Request = {
|
|
11
|
-
data: ReturnType<Router['match']>;
|
|
11
|
+
data: ReturnType<Router['match']> & Record<PropertyKey, unknown>;
|
|
12
|
+
href: string;
|
|
12
13
|
hostname: string;
|
|
13
14
|
method: string;
|
|
15
|
+
origin: string;
|
|
14
16
|
path: string;
|
|
17
|
+
port: string;
|
|
18
|
+
protocol: string;
|
|
19
|
+
query: Record<string, unknown>;
|
|
15
20
|
subdomain?: string;
|
|
16
21
|
};
|
|
17
|
-
type Responder = <T>(request: T) => Promise<
|
|
22
|
+
type Responder = <T, U>(request: T) => Promise<U> | U;
|
|
18
23
|
export { Middleware, Next, Options, Request, Responder, Route, Router };
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "ICJR",
|
|
3
|
+
"dependencies": {
|
|
4
|
+
"@esportsplus/middleware": "^0.0.4"
|
|
5
|
+
},
|
|
3
6
|
"devDependencies": {
|
|
4
|
-
"@esportsplus/
|
|
7
|
+
"@esportsplus/typescript": "^0.0.1"
|
|
5
8
|
},
|
|
6
9
|
"main": "./build/index.js",
|
|
7
10
|
"name": "@esportsplus/routing",
|
|
@@ -13,8 +16,5 @@
|
|
|
13
16
|
"prepublishOnly": "npm run build"
|
|
14
17
|
},
|
|
15
18
|
"types": "./build/index.d.ts",
|
|
16
|
-
"version": "0.0.
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"@esportsplus/middleware": "^0.0.4"
|
|
19
|
-
}
|
|
19
|
+
"version": "0.0.13"
|
|
20
20
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import spa from './spa';
|
|
2
2
|
import middleware from './middleware';
|
|
3
3
|
import router from './router';
|
|
4
4
|
import slugify from './slugify';
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
export {
|
|
7
|
+
export { spa, middleware, router, slugify };
|
|
8
8
|
export * from './types';
|
package/src/router/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATIC } from "~/
|
|
1
|
+
import { STATIC } from "~/constants";
|
|
2
2
|
import { Options } from '~/types';
|
|
3
3
|
import { Node } from './node';
|
|
4
4
|
import { normalize, radixkey } from './path';
|
|
@@ -8,13 +8,13 @@ import { Route } from './route';
|
|
|
8
8
|
let { isArray } = Array;
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
function set(route: Route, key: keyof Route, value?:
|
|
11
|
+
function set(route: Route, key: keyof Route, value?: unknown) {
|
|
12
12
|
if (!value) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
if (!route[key]) {
|
|
17
|
-
(route[key] as
|
|
17
|
+
(route[key] as unknown) = value;
|
|
18
18
|
}
|
|
19
19
|
else if (typeof value === 'string') {
|
|
20
20
|
if (typeof route[key] === 'string') {
|
|
@@ -23,7 +23,7 @@ function set(route: Route, key: keyof Route, value?: any) {
|
|
|
23
23
|
}
|
|
24
24
|
else if (isArray(value)) {
|
|
25
25
|
if (isArray(route[key])) {
|
|
26
|
-
(route[key] as
|
|
26
|
+
(route[key] as unknown[]).push( ...value );
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -43,15 +43,15 @@ class Router {
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
private add(radixkey: string, route: Route) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (node.type === STATIC) {
|
|
46
|
+
if (radixkey.indexOf(':') === -1 || this.root.add(radixkey, route).type === STATIC) {
|
|
49
47
|
if (this.static[radixkey]) {
|
|
50
48
|
throw new Error(`Routing: static path '${radixkey}' is already in use`);
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
this.static[radixkey] = route;
|
|
54
52
|
}
|
|
53
|
+
|
|
54
|
+
return this;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
private route({ middleware, name, path, responder, subdomain }: Options) {
|
|
@@ -106,10 +106,8 @@ class Router {
|
|
|
106
106
|
match(method: string, path: string, subdomain?: string | null): ReturnType<Node['find']> {
|
|
107
107
|
let key = radixkey(path, { method, subdomain });
|
|
108
108
|
|
|
109
|
-
if (this.static
|
|
110
|
-
return {
|
|
111
|
-
route: this.static[key]
|
|
112
|
-
};
|
|
109
|
+
if (key in this.static) {
|
|
110
|
+
return { route: this.static[key] };
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
return this.root.find(key);
|
|
@@ -155,6 +153,8 @@ class Router {
|
|
|
155
153
|
this.subdomains.push(route.subdomain);
|
|
156
154
|
}
|
|
157
155
|
}
|
|
156
|
+
|
|
157
|
+
return this;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
post(options: Options) {
|
|
@@ -168,7 +168,7 @@ class Router {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
uri(name: string, values: unknown[] = []) {
|
|
171
|
-
let path = this.routes
|
|
171
|
+
let path = this.routes[name]?.path;
|
|
172
172
|
|
|
173
173
|
if (!path) {
|
|
174
174
|
throw new Error(`Routing: route name '${name}' does not exist or it does not provide a path`);
|
package/src/router/node.ts
CHANGED
package/src/spa.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Request, Router } from './types';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
type Cache = {
|
|
5
|
+
factory: typeof request;
|
|
6
|
+
state: Request;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
let cache: Cache[] = [];
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
function update() {
|
|
14
|
+
for (let i = 0, n = cache.length; i < n; i++) {
|
|
15
|
+
let { factory, state } = cache[i],
|
|
16
|
+
values: Request = factory();
|
|
17
|
+
|
|
18
|
+
for (let key in values) {
|
|
19
|
+
// @ts-ignore STFU
|
|
20
|
+
state[key] = values[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
const back = () => window.history.back();
|
|
27
|
+
|
|
28
|
+
const forward = () => window.history.forward();
|
|
29
|
+
|
|
30
|
+
const request = (url: string = window?.location?.href || ''): Request => {
|
|
31
|
+
let { hash, hostname, href, origin, port, protocol } = new URL( url ),
|
|
32
|
+
path = hash?.replace('#/', '/')?.split('?') || ['/', ''];
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
data: {},
|
|
36
|
+
href,
|
|
37
|
+
hostname,
|
|
38
|
+
method: 'GET',
|
|
39
|
+
origin,
|
|
40
|
+
path: path[0],
|
|
41
|
+
port,
|
|
42
|
+
protocol,
|
|
43
|
+
query: Object.fromEntries( (new URLSearchParams(path[1])).entries() )
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
export default (router: Router, state: Cache['state'], factory?: Cache['factory']) => {
|
|
49
|
+
cache.push({
|
|
50
|
+
factory: factory || request,
|
|
51
|
+
state
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
update();
|
|
55
|
+
|
|
56
|
+
window.addEventListener('popstate', update);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
back,
|
|
60
|
+
forward,
|
|
61
|
+
redirect: (path: string, { state, values }: { state?: Record<PropertyKey, unknown>; values?: unknown[] }) => {
|
|
62
|
+
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
63
|
+
return window.location.replace(path);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let uri = router.uri(path, values || []);
|
|
67
|
+
|
|
68
|
+
if (uri[0] === '/') {
|
|
69
|
+
uri = '#' + uri;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
window.history.pushState(state || {}, '', uri);
|
|
73
|
+
},
|
|
74
|
+
request: factory || request,
|
|
75
|
+
uri: (path: string, values: unknown[] = []) => {
|
|
76
|
+
let uri = router.uri(path, values || []);
|
|
77
|
+
|
|
78
|
+
if (uri[0] === '/') {
|
|
79
|
+
uri = '#' + uri;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return uri;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -11,14 +11,19 @@ type Options = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
type Request = {
|
|
14
|
-
data: ReturnType<Router['match']>;
|
|
14
|
+
data: ReturnType<Router['match']> & Record<PropertyKey, unknown>;
|
|
15
|
+
href: string;
|
|
15
16
|
hostname: string;
|
|
16
17
|
method: string;
|
|
18
|
+
origin: string;
|
|
17
19
|
path: string;
|
|
20
|
+
port: string;
|
|
21
|
+
protocol: string;
|
|
22
|
+
query: Record<string, unknown>;
|
|
18
23
|
subdomain?: string;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
type Responder = <T>(request: T) => Promise<
|
|
26
|
+
type Responder = <T, U>(request: T) => Promise<U> | U;
|
|
22
27
|
|
|
23
28
|
|
|
24
29
|
export { Middleware, Next, Options, Request, Responder, Route, Router };
|
package/tsconfig.json
CHANGED
package/src/hash.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Router } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
let cache: {
|
|
5
|
-
factory: typeof request;
|
|
6
|
-
state: Record<PropertyKey, unknown>;
|
|
7
|
-
}[] = [],
|
|
8
|
-
registered = false;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function update() {
|
|
12
|
-
for (let i = 0, n = cache.length; i < n; i++) {
|
|
13
|
-
let { factory, state } = cache[i],
|
|
14
|
-
values = factory();
|
|
15
|
-
|
|
16
|
-
for (let key in values) {
|
|
17
|
-
state[key] = values[key as keyof typeof values];
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const back = () => window.history.back();
|
|
24
|
-
|
|
25
|
-
const forward = () => window.history.forward();
|
|
26
|
-
|
|
27
|
-
const listener = {
|
|
28
|
-
register: (factory: typeof cache[0]['factory'], state: typeof cache[0]['state']) => {
|
|
29
|
-
cache.push({ factory, state });
|
|
30
|
-
|
|
31
|
-
if (!registered) {
|
|
32
|
-
registered = true;
|
|
33
|
-
update();
|
|
34
|
-
|
|
35
|
-
window.addEventListener('popstate', update);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return () => {
|
|
39
|
-
listener.remove(state);
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
remove: (state: typeof cache[0]['state']) => {
|
|
43
|
-
for (let i = 0, n = cache.length; i < n; i++) {
|
|
44
|
-
if (cache[i].state !== state) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
cache[i] = cache[n - 1];
|
|
49
|
-
cache.pop();
|
|
50
|
-
|
|
51
|
-
if (cache.length === 0) {
|
|
52
|
-
window.removeEventListener('popstate', update);
|
|
53
|
-
}
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const factory = {
|
|
60
|
-
redirect: (router: Router) => {
|
|
61
|
-
return (path: string, { state, values }: { state?: Record<PropertyKey, unknown>; values?: unknown[] }) => {
|
|
62
|
-
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
63
|
-
return window.location.replace(path);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let uri = router.uri(path, values || []);
|
|
67
|
-
|
|
68
|
-
if (uri[0] === '/') {
|
|
69
|
-
uri = '#' + uri;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
window.history.pushState(state || {}, '', uri);
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
uri: (router: Router) => {
|
|
76
|
-
return (path: string, values: unknown[] = []) => {
|
|
77
|
-
let uri = router.uri(path, values || []);
|
|
78
|
-
|
|
79
|
-
if (uri[0] === '/') {
|
|
80
|
-
uri = '#' + uri;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return uri;
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const request = (url: string = window?.location?.href || '') => {
|
|
89
|
-
let { hash, hostname, href, origin, port, protocol } = new URL( url ),
|
|
90
|
-
path = hash?.replace('#/', '/')?.split('?') || ['/', ''];
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
href,
|
|
94
|
-
hostname,
|
|
95
|
-
method: 'GET',
|
|
96
|
-
origin,
|
|
97
|
-
path: path[0],
|
|
98
|
-
port,
|
|
99
|
-
protocol,
|
|
100
|
-
query: Object.fromEntries( (new URLSearchParams(path[1])).entries() )
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
export default { back, factory, forward, listener, request };
|
|
106
|
-
export { back, factory, forward, listener, request };
|
|
File without changes
|