19 changed files with 1239 additions and 5 deletions
-
1node_modules/__ngcc_entry_points__.json
-
258node_modules/ngx-cookie-service/README.md
-
208node_modules/ngx-cookie-service/esm2020/lib/cookie.service.mjs
-
5node_modules/ngx-cookie-service/esm2020/ngx-cookie-service.mjs
-
5node_modules/ngx-cookie-service/esm2020/public-api.mjs
-
219node_modules/ngx-cookie-service/fesm2015/ngx-cookie-service.mjs
-
1node_modules/ngx-cookie-service/fesm2015/ngx-cookie-service.mjs.map
-
217node_modules/ngx-cookie-service/fesm2020/ngx-cookie-service.mjs
-
1node_modules/ngx-cookie-service/fesm2020/ngx-cookie-service.mjs.map
-
127node_modules/ngx-cookie-service/lib/cookie.service.d.ts
-
5node_modules/ngx-cookie-service/ngx-cookie-service.d.ts
-
144node_modules/ngx-cookie-service/package.json
-
1node_modules/ngx-cookie-service/public-api.d.ts
-
8package-lock.json
-
1package.json
-
4src/app/annual-health-checkup/annual-health-checkup.component.ts
-
6src/app/annual-health-checkup/generate-letter/generate-letter.component.ts
-
29src/app/annual-health-checkup/generate-letter/generate-letter.service.ts
-
4src/app/app.module.ts
1
node_modules/__ngcc_entry_points__.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,258 @@ |
|||||
|
# NGX Cookie Service |
||||
|
|
||||
|
<p align="center"> |
||||
|
|
||||
|
 |
||||
|
<a href="https://www.npmjs.com/ngx-cookie-service"> |
||||
|
<img src="https://img.shields.io/npm/v/ngx-cookie-service.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Ngx Cookie Service on npm" /> |
||||
|
</a> |
||||
|
<a href="https://gitter.im/ngx-cookie-service/community"> |
||||
|
<img src="https://badges.gitter.im/ngx-cookie-service/community.svg" alt="Chat in Gitter" /> |
||||
|
</a> |
||||
|
[](https://discord.gg/N3xc4Jfb) |
||||
|
|
||||
|
</p> |
||||
|
|
||||
|
Angular service to read, set and delete browser cookies. Originally based on the [ng2-cookies](https://www.npmjs.com/package/ng2-cookies) library. The experienced team behind [Studytube](https://www.studytube.nl/) will take care of our cookie service from now on. |
||||
|
|
||||
|
> Note: `ViewEngine` support has been removed on 13.x.x. See [compatability matrix](https://github.com/stevermeister/ngx-cookie-service#supported-versions) for details |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
```bash |
||||
|
npm install ngx-cookie-service --save |
||||
|
|
||||
|
# or |
||||
|
|
||||
|
yarn add ngx-cookie-service |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
Add the cookie service to your `app.module.ts` as a provider: |
||||
|
|
||||
|
```typescript |
||||
|
import { CookieService } from 'ngx-cookie-service'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
... |
||||
|
providers: |
||||
|
[CookieService], |
||||
|
... |
||||
|
}) |
||||
|
|
||||
|
export class AppModule { |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
Then, import and inject it into a constructor: |
||||
|
|
||||
|
```typescript |
||||
|
constructor(private |
||||
|
cookieService: CookieService |
||||
|
) |
||||
|
{ |
||||
|
this.cookieService.set('Test', 'Hello World'); |
||||
|
this.cookieValue = this.cookieService.get('Test'); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
That's it! |
||||
|
|
||||
|
## Server Side Rendering (Coming Soon) |
||||
|
|
||||
|
`ngx-cookie-service` supports Server Side Rendering (SSR) through Angular Universal. By default, browser cookies are not |
||||
|
available in SSR because `document` object is not available. To overcome this, navigate to `server.ts` file in your SSR |
||||
|
project, and replace the following code |
||||
|
|
||||
|
```typescript |
||||
|
server.get('*', (req, res) => { |
||||
|
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
with this |
||||
|
|
||||
|
```typescript |
||||
|
server.get('*', (req, res) => { |
||||
|
res.render(indexHtml, { |
||||
|
req, |
||||
|
providers: [ |
||||
|
{ provide: APP_BASE_HREF, useValue: req.baseUrl }, |
||||
|
{ provide: 'REQUEST', useValue: req }, |
||||
|
{ provide: 'RESPONSE', useValue: res }, |
||||
|
], |
||||
|
}); |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
This will make sure the cookies are available in `REQUEST` object, and the `ngx-cookie-service` can use `REQUEST.cookies` to access the |
||||
|
cookies in SSR. Then proceed to use `ngx-cookie-service` as usual. See |
||||
|
the [sample repo](https://github.com/pavankjadda/angular-ssr-docker) for more details. |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
https://stackblitz.com/edit/angular-ivy-1lrgdt?file=src%2Fapp%2Fapp.component.ts |
||||
|
|
||||
|
## Supported Versions |
||||
|
|
||||
|
`ViewEngine` support has been removed on 13.x.x. For Angular versions 13.x.x or later use the latest version of the |
||||
|
library. For versions <=12.x.x, use 12.0.3 version |
||||
|
|
||||
|
| Angular Version | Supported Version | |
||||
|
| ---------------------- | ----------------- | |
||||
|
| 13.x.x or later (Ivy) | 13.x.x or later | |
||||
|
| <=12.x.x (View Engine) | 12.0.3 | |
||||
|
|
||||
|
# API |
||||
|
|
||||
|
## check( name: string ): boolean; |
||||
|
|
||||
|
```typescript |
||||
|
const cookieExists: boolean = cookieService.check('test'); |
||||
|
``` |
||||
|
|
||||
|
Checks if a cookie with the given`name` can be accessed or found. |
||||
|
|
||||
|
## get( name: string ): string; |
||||
|
|
||||
|
```typescript |
||||
|
const value: string = cookieService.get('test'); |
||||
|
``` |
||||
|
|
||||
|
Gets the value of the cookie with the specified `name`. |
||||
|
|
||||
|
## getAll(): {}; |
||||
|
|
||||
|
```typescript |
||||
|
const allCookies: {} = cookieService.getAll(); |
||||
|
``` |
||||
|
|
||||
|
Returns a map of key-value pairs for cookies that can be accessed. |
||||
|
|
||||
|
## set( name: string, value: string, expires?: number | Date, path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'Strict' | 'None' ): void; |
||||
|
|
||||
|
## set( name: string, value: string, options?: { expires?: number | Date, path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'None' | 'Strict'}): void; |
||||
|
|
||||
|
```typescript |
||||
|
cookieService.set('test', 'Hello World'); |
||||
|
cookieService.set('test', 'Hello World', { expires: 2, sameSite: 'Lax' }); |
||||
|
``` |
||||
|
|
||||
|
Sets a cookie with the specified `name` and `value`. It is good practice to specify a path. If you are unsure about the |
||||
|
path value, use `'/'`. If no path or domain is explicitly defined, the current location is assumed. `sameSite` defaults |
||||
|
to `Lax`. |
||||
|
|
||||
|
**Important:** For security reasons, it is not possible to define cookies for other domains. Browsers do not allow this. |
||||
|
Read [this](https://stackoverflow.com/a/1063760) and [this](https://stackoverflow.com/a/17777005/1007003) StackOverflow |
||||
|
answer for a more in-depth explanation. |
||||
|
|
||||
|
**Important:** Browsers do not accept cookies flagged sameSite = 'None' if secure flag isn't set as well. CookieService |
||||
|
will override the secure flag to true if sameSite='None'. |
||||
|
|
||||
|
## delete( name: string, path?: string, domain?: string, secure?: boolean, sameSite: 'Lax' | 'None' | 'Strict' = 'Lax'): void; |
||||
|
|
||||
|
```typescript |
||||
|
cookieService.delete('test'); |
||||
|
``` |
||||
|
|
||||
|
Deletes a cookie with the specified `name`. It is best practice to always define a path. If you are unsure about the |
||||
|
path value, use `'/'`. |
||||
|
|
||||
|
**Important:** For security reasons, it is not possible to delete cookies for other domains. Browsers do not allow this. |
||||
|
Read [this](https://stackoverflow.com/a/1063760) and [this](https://stackoverflow.com/a/17777005/1007003) StackOverflow |
||||
|
answer for a more in-depth explanation. |
||||
|
|
||||
|
## deleteAll( path?: string, domain?: string, secure?: boolean, sameSite: 'Lax' | 'None' | 'Strict' = 'Lax' ): void; |
||||
|
|
||||
|
```typescript |
||||
|
cookieService.deleteAll(); |
||||
|
``` |
||||
|
|
||||
|
Deletes all cookies that can currently be accessed. It is best practice to always define a path. If you are unsure about |
||||
|
the path value, use `'/'`. |
||||
|
|
||||
|
# FAQ |
||||
|
|
||||
|
## General tips |
||||
|
|
||||
|
Checking out the following resources usually solves most of the problems people seem to have with this cookie service: |
||||
|
|
||||
|
- [article about cookies in general @MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) (recommended read!) |
||||
|
- [common localhost problems @StackOverflow](https://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain) |
||||
|
- [problems with secure cookies @StackOverflow](https://stackoverflow.com/questions/8064318/how-to-read-a-secure-cookie-using-javascript) |
||||
|
- [how do browser cookie domains work? @StackOverflow](https://stackoverflow.com/questions/1062963/how-do-browser-cookie-domains-work) |
||||
|
- [get cookies from different paths](https://github.com/7leads/ngx-cookie-service/issues/7#issuecomment-351321518) |
||||
|
|
||||
|
The following general steps are usually very helpful when debugging problems with this cookie service or cookies in |
||||
|
general: |
||||
|
|
||||
|
- check out if there are any [open](https://github.com/stevermeister/ngx-cookie-service/issues) |
||||
|
or [closed](https://github.com/stevermeister/ngx-cookie-service/issues?q=is%3Aissue+is%3Aclosed) issues that answer |
||||
|
your question |
||||
|
- check out the actual value(s) of `document.cookie` |
||||
|
- does it work if you use `document.cookie` manually (i.e. in a console of your choice)? |
||||
|
- set explicit paths for your cookies |
||||
|
- [explain to your local rubber duck why your code should work and why it (probably) does not](https://en.wikipedia.org/wiki/Rubber_duck_debugging) |
||||
|
|
||||
|
# I am always getting a "token missing" or "no provider" error. |
||||
|
|
||||
|
Package managers are a well known source of frustration. If you have "token missing" or "no provider" errors, a simple |
||||
|
re-installation of your node modules might suffice: |
||||
|
|
||||
|
``` |
||||
|
rm -rf node_modules |
||||
|
yarn # or `npm install` |
||||
|
``` |
||||
|
|
||||
|
## I have a problem with framework X or library Y. What can I do? |
||||
|
|
||||
|
Please be aware that we cannot help you with problems that are out of scope. For example, we cannot debug a Symfony or |
||||
|
Springboot application for you. In that case, you are better off asking the nice folks over |
||||
|
at [StackOverflow](https://stackoverflow.com/) for help. |
||||
|
|
||||
|
## Do you support Angular Universal? |
||||
|
|
||||
|
There is an [issue](https://github.com/7leads/ngx-cookie-service/issues/1) for that. Check |
||||
|
out [this comment](https://github.com/7leads/ngx-cookie-service/issues/1#issuecomment-361150174) for more information |
||||
|
about future support. |
||||
|
|
||||
|
# Opening issues |
||||
|
|
||||
|
Please make sure to check out our FAQ before you open a new issue. Also, try to give us as much information as you can |
||||
|
when you open an issue. Maybe you can even supply a test environment or test cases, if necessary? |
||||
|
|
||||
|
# Contributing |
||||
|
|
||||
|
We are happy to accept pull requests or test cases for things that do not work. Feel free to submit one of those. |
||||
|
|
||||
|
However, we will only accept pull requests that pass all tests and include some new ones (as long as it makes sense to |
||||
|
add them, of course). |
||||
|
|
||||
|
- [Open a new pull request](https://github.com/stevermeister/ngx-cookie-service/compare) |
||||
|
|
||||
|
# Author |
||||
|
|
||||
|
This cookie service is brought to you by [7leads GmbH](http://www.7leads.org/). We built it for one of our apps, because |
||||
|
the other cookie packages we found were either not designed "the Angular way" or caused trouble during AOT compilation. |
||||
|
|
||||
|
# Contributors |
||||
|
|
||||
|
Thanks to all contributors: |
||||
|
|
||||
|
- [paroe](https://github.com/paroe) |
||||
|
- [CunningFatalist](https://github.com/CunningFatalist) |
||||
|
- [kthy](https://github.com/kthy) |
||||
|
- [JaredClemence](https://github.com/JaredClemence) |
||||
|
- [flakolefluk](https://github.com/flakolefluk) |
||||
|
- [mattbanks](https://github.com/mattbanks) |
||||
|
- [DBaker85](https://github.com/DBaker85) |
||||
|
- [mattlewis92](https://github.com/mattlewis92) |
||||
|
- [IceBreakerG](https://github.com/IceBreakerG) |
||||
|
- [rojedalopez](https://github.com/rojedalopez) |
||||
|
- [Nikel163](https://github.com/Nikel163) |
||||
|
- [pavankjadda](https://github.com/pavankjadda) |
||||
|
|
||||
|
# License |
||||
|
|
||||
|
[MIT](https://github.com/stevermeister/ngx-cookie-service/blob/master/LICENSE) |
208
node_modules/ngx-cookie-service/esm2020/lib/cookie.service.mjs
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,5 @@ |
|||||
|
/** |
||||
|
* Generated bundle index. Do not edit. |
||||
|
*/ |
||||
|
export * from './public-api'; |
||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWNvb2tpZS1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvbmd4LWNvb2tpZS1zZXJ2aWNlL3NyYy9uZ3gtY29va2llLXNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ== |
@ -0,0 +1,5 @@ |
|||||
|
/* |
||||
|
* Public API Surface of ngx-cookie-service |
||||
|
*/ |
||||
|
export * from './lib/cookie.service'; |
||||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25neC1jb29raWUtc2VydmljZS9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsc0JBQXNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIG5neC1jb29raWUtc2VydmljZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL2Nvb2tpZS5zZXJ2aWNlJztcbiJdfQ== |
@ -0,0 +1,219 @@ |
|||||
|
import * as i0 from '@angular/core'; |
||||
|
import { PLATFORM_ID, Injectable, Inject } from '@angular/core'; |
||||
|
import { isPlatformBrowser, DOCUMENT } from '@angular/common'; |
||||
|
|
||||
|
// This service is based on the `ng2-cookies` package which sadly is not a service and does |
||||
|
class CookieService { |
||||
|
constructor(document, |
||||
|
// Get the `PLATFORM_ID` so we can check if we're in a browser. |
||||
|
platformId) { |
||||
|
this.document = document; |
||||
|
this.platformId = platformId; |
||||
|
this.documentIsAccessible = isPlatformBrowser(this.platformId); |
||||
|
} |
||||
|
/** |
||||
|
* Get cookie Regular Expression |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property RegExp |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
static getCookieRegExp(name) { |
||||
|
const escapedName = name.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi, '\\$1'); |
||||
|
return new RegExp('(?:^' + escapedName + '|;\\s*' + escapedName + ')=(.*?)(?:;|$)', 'g'); |
||||
|
} |
||||
|
/** |
||||
|
* Gets the unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @param encodedURIComponent A value representing an encoded URI component. |
||||
|
* |
||||
|
* @returns The unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
static safeDecodeURIComponent(encodedURIComponent) { |
||||
|
try { |
||||
|
return decodeURIComponent(encodedURIComponent); |
||||
|
} |
||||
|
catch (_a) { |
||||
|
// probably it is not uri encoded. return as is |
||||
|
return encodedURIComponent; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* Return `true` if {@link Document} is accessible, otherwise return `false` |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns boolean - whether cookie with specified name exists |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
check(name) { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return false; |
||||
|
} |
||||
|
name = encodeURIComponent(name); |
||||
|
const regExp = CookieService.getCookieRegExp(name); |
||||
|
return regExp.test(this.document.cookie); |
||||
|
} |
||||
|
/** |
||||
|
* Get cookies by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property value |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
get(name) { |
||||
|
if (this.documentIsAccessible && this.check(name)) { |
||||
|
name = encodeURIComponent(name); |
||||
|
const regExp = CookieService.getCookieRegExp(name); |
||||
|
const result = regExp.exec(this.document.cookie); |
||||
|
return result[1] ? CookieService.safeDecodeURIComponent(result[1]) : ''; |
||||
|
} |
||||
|
else { |
||||
|
return ''; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* Get all cookies in JSON format |
||||
|
* |
||||
|
* @returns all the cookies in json |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
getAll() { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return {}; |
||||
|
} |
||||
|
const cookies = {}; |
||||
|
const document = this.document; |
||||
|
if (document.cookie && document.cookie !== '') { |
||||
|
document.cookie.split(';').forEach((currentCookie) => { |
||||
|
const [cookieName, cookieValue] = currentCookie.split('='); |
||||
|
cookies[CookieService.safeDecodeURIComponent(cookieName.replace(/^ /, ''))] = CookieService.safeDecodeURIComponent(cookieValue); |
||||
|
}); |
||||
|
} |
||||
|
return cookies; |
||||
|
} |
||||
|
set(name, value, expiresOrOptions, path, domain, secure, sameSite) { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
if (typeof expiresOrOptions === 'number' || expiresOrOptions instanceof Date || path || domain || secure || sameSite) { |
||||
|
const optionsBody = { |
||||
|
expires: expiresOrOptions, |
||||
|
path, |
||||
|
domain, |
||||
|
secure, |
||||
|
sameSite: sameSite ? sameSite : 'Lax', |
||||
|
}; |
||||
|
this.set(name, value, optionsBody); |
||||
|
return; |
||||
|
} |
||||
|
let cookieString = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';'; |
||||
|
const options = expiresOrOptions ? expiresOrOptions : {}; |
||||
|
if (options.expires) { |
||||
|
if (typeof options.expires === 'number') { |
||||
|
const dateExpires = new Date(new Date().getTime() + options.expires * 1000 * 60 * 60 * 24); |
||||
|
cookieString += 'expires=' + dateExpires.toUTCString() + ';'; |
||||
|
} |
||||
|
else { |
||||
|
cookieString += 'expires=' + options.expires.toUTCString() + ';'; |
||||
|
} |
||||
|
} |
||||
|
if (options.path) { |
||||
|
cookieString += 'path=' + options.path + ';'; |
||||
|
} |
||||
|
if (options.domain) { |
||||
|
cookieString += 'domain=' + options.domain + ';'; |
||||
|
} |
||||
|
if (options.secure === false && options.sameSite === 'None') { |
||||
|
options.secure = true; |
||||
|
console.warn(`[ngx-cookie-service] Cookie ${name} was forced with secure flag because sameSite=None.` + |
||||
|
`More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`); |
||||
|
} |
||||
|
if (options.secure) { |
||||
|
cookieString += 'secure;'; |
||||
|
} |
||||
|
if (!options.sameSite) { |
||||
|
options.sameSite = 'Lax'; |
||||
|
} |
||||
|
cookieString += 'sameSite=' + options.sameSite + ';'; |
||||
|
this.document.cookie = cookieString; |
||||
|
} |
||||
|
/** |
||||
|
* Delete cookie by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Cookie secure flag |
||||
|
* @param sameSite Cookie sameSite flag - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
delete(name, path, domain, secure, sameSite = 'Lax') { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
const expiresDate = new Date('Thu, 01 Jan 1970 00:00:01 GMT'); |
||||
|
this.set(name, '', { expires: expiresDate, path, domain, secure, sameSite }); |
||||
|
} |
||||
|
/** |
||||
|
* Delete all cookies |
||||
|
* |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Is the Cookie secure |
||||
|
* @param sameSite Is the cookie same site |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
deleteAll(path, domain, secure, sameSite = 'Lax') { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
const cookies = this.getAll(); |
||||
|
for (const cookieName in cookies) { |
||||
|
if (cookies.hasOwnProperty(cookieName)) { |
||||
|
this.delete(cookieName, path, domain, secure, sameSite); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
CookieService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); |
||||
|
CookieService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, providedIn: 'root' }); |
||||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, decorators: [{ |
||||
|
type: Injectable, |
||||
|
args: [{ |
||||
|
providedIn: 'root', |
||||
|
}] |
||||
|
}], ctorParameters: function () { |
||||
|
return [{ type: Document, decorators: [{ |
||||
|
type: Inject, |
||||
|
args: [DOCUMENT] |
||||
|
}] }, { type: undefined, decorators: [{ |
||||
|
type: Inject, |
||||
|
args: [PLATFORM_ID] |
||||
|
}] }]; |
||||
|
} }); |
||||
|
|
||||
|
/* |
||||
|
* Public API Surface of ngx-cookie-service |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* Generated bundle index. Do not edit. |
||||
|
*/ |
||||
|
|
||||
|
export { CookieService }; |
||||
|
//# sourceMappingURL=ngx-cookie-service.mjs.map |
1
node_modules/ngx-cookie-service/fesm2015/ngx-cookie-service.mjs.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,217 @@ |
|||||
|
import * as i0 from '@angular/core'; |
||||
|
import { PLATFORM_ID, Injectable, Inject } from '@angular/core'; |
||||
|
import { isPlatformBrowser, DOCUMENT } from '@angular/common'; |
||||
|
|
||||
|
// This service is based on the `ng2-cookies` package which sadly is not a service and does |
||||
|
class CookieService { |
||||
|
constructor(document, |
||||
|
// Get the `PLATFORM_ID` so we can check if we're in a browser. |
||||
|
platformId) { |
||||
|
this.document = document; |
||||
|
this.platformId = platformId; |
||||
|
this.documentIsAccessible = isPlatformBrowser(this.platformId); |
||||
|
} |
||||
|
/** |
||||
|
* Get cookie Regular Expression |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property RegExp |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
static getCookieRegExp(name) { |
||||
|
const escapedName = name.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi, '\\$1'); |
||||
|
return new RegExp('(?:^' + escapedName + '|;\\s*' + escapedName + ')=(.*?)(?:;|$)', 'g'); |
||||
|
} |
||||
|
/** |
||||
|
* Gets the unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @param encodedURIComponent A value representing an encoded URI component. |
||||
|
* |
||||
|
* @returns The unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
static safeDecodeURIComponent(encodedURIComponent) { |
||||
|
try { |
||||
|
return decodeURIComponent(encodedURIComponent); |
||||
|
} |
||||
|
catch { |
||||
|
// probably it is not uri encoded. return as is |
||||
|
return encodedURIComponent; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* Return `true` if {@link Document} is accessible, otherwise return `false` |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns boolean - whether cookie with specified name exists |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
check(name) { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return false; |
||||
|
} |
||||
|
name = encodeURIComponent(name); |
||||
|
const regExp = CookieService.getCookieRegExp(name); |
||||
|
return regExp.test(this.document.cookie); |
||||
|
} |
||||
|
/** |
||||
|
* Get cookies by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property value |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
get(name) { |
||||
|
if (this.documentIsAccessible && this.check(name)) { |
||||
|
name = encodeURIComponent(name); |
||||
|
const regExp = CookieService.getCookieRegExp(name); |
||||
|
const result = regExp.exec(this.document.cookie); |
||||
|
return result[1] ? CookieService.safeDecodeURIComponent(result[1]) : ''; |
||||
|
} |
||||
|
else { |
||||
|
return ''; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* Get all cookies in JSON format |
||||
|
* |
||||
|
* @returns all the cookies in json |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
getAll() { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return {}; |
||||
|
} |
||||
|
const cookies = {}; |
||||
|
const document = this.document; |
||||
|
if (document.cookie && document.cookie !== '') { |
||||
|
document.cookie.split(';').forEach((currentCookie) => { |
||||
|
const [cookieName, cookieValue] = currentCookie.split('='); |
||||
|
cookies[CookieService.safeDecodeURIComponent(cookieName.replace(/^ /, ''))] = CookieService.safeDecodeURIComponent(cookieValue); |
||||
|
}); |
||||
|
} |
||||
|
return cookies; |
||||
|
} |
||||
|
set(name, value, expiresOrOptions, path, domain, secure, sameSite) { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
if (typeof expiresOrOptions === 'number' || expiresOrOptions instanceof Date || path || domain || secure || sameSite) { |
||||
|
const optionsBody = { |
||||
|
expires: expiresOrOptions, |
||||
|
path, |
||||
|
domain, |
||||
|
secure, |
||||
|
sameSite: sameSite ? sameSite : 'Lax', |
||||
|
}; |
||||
|
this.set(name, value, optionsBody); |
||||
|
return; |
||||
|
} |
||||
|
let cookieString = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';'; |
||||
|
const options = expiresOrOptions ? expiresOrOptions : {}; |
||||
|
if (options.expires) { |
||||
|
if (typeof options.expires === 'number') { |
||||
|
const dateExpires = new Date(new Date().getTime() + options.expires * 1000 * 60 * 60 * 24); |
||||
|
cookieString += 'expires=' + dateExpires.toUTCString() + ';'; |
||||
|
} |
||||
|
else { |
||||
|
cookieString += 'expires=' + options.expires.toUTCString() + ';'; |
||||
|
} |
||||
|
} |
||||
|
if (options.path) { |
||||
|
cookieString += 'path=' + options.path + ';'; |
||||
|
} |
||||
|
if (options.domain) { |
||||
|
cookieString += 'domain=' + options.domain + ';'; |
||||
|
} |
||||
|
if (options.secure === false && options.sameSite === 'None') { |
||||
|
options.secure = true; |
||||
|
console.warn(`[ngx-cookie-service] Cookie ${name} was forced with secure flag because sameSite=None.` + |
||||
|
`More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`); |
||||
|
} |
||||
|
if (options.secure) { |
||||
|
cookieString += 'secure;'; |
||||
|
} |
||||
|
if (!options.sameSite) { |
||||
|
options.sameSite = 'Lax'; |
||||
|
} |
||||
|
cookieString += 'sameSite=' + options.sameSite + ';'; |
||||
|
this.document.cookie = cookieString; |
||||
|
} |
||||
|
/** |
||||
|
* Delete cookie by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Cookie secure flag |
||||
|
* @param sameSite Cookie sameSite flag - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
delete(name, path, domain, secure, sameSite = 'Lax') { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
const expiresDate = new Date('Thu, 01 Jan 1970 00:00:01 GMT'); |
||||
|
this.set(name, '', { expires: expiresDate, path, domain, secure, sameSite }); |
||||
|
} |
||||
|
/** |
||||
|
* Delete all cookies |
||||
|
* |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Is the Cookie secure |
||||
|
* @param sameSite Is the cookie same site |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
deleteAll(path, domain, secure, sameSite = 'Lax') { |
||||
|
if (!this.documentIsAccessible) { |
||||
|
return; |
||||
|
} |
||||
|
const cookies = this.getAll(); |
||||
|
for (const cookieName in cookies) { |
||||
|
if (cookies.hasOwnProperty(cookieName)) { |
||||
|
this.delete(cookieName, path, domain, secure, sameSite); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
CookieService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); |
||||
|
CookieService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, providedIn: 'root' }); |
||||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: CookieService, decorators: [{ |
||||
|
type: Injectable, |
||||
|
args: [{ |
||||
|
providedIn: 'root', |
||||
|
}] |
||||
|
}], ctorParameters: function () { return [{ type: Document, decorators: [{ |
||||
|
type: Inject, |
||||
|
args: [DOCUMENT] |
||||
|
}] }, { type: undefined, decorators: [{ |
||||
|
type: Inject, |
||||
|
args: [PLATFORM_ID] |
||||
|
}] }]; } }); |
||||
|
|
||||
|
/* |
||||
|
* Public API Surface of ngx-cookie-service |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* Generated bundle index. Do not edit. |
||||
|
*/ |
||||
|
|
||||
|
export { CookieService }; |
||||
|
//# sourceMappingURL=ngx-cookie-service.mjs.map |
1
node_modules/ngx-cookie-service/fesm2020/ngx-cookie-service.mjs.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,127 @@ |
|||||
|
import * as i0 from "@angular/core"; |
||||
|
export declare class CookieService { |
||||
|
private document; |
||||
|
private platformId; |
||||
|
private readonly documentIsAccessible; |
||||
|
constructor(document: Document, platformId: any); |
||||
|
/** |
||||
|
* Get cookie Regular Expression |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property RegExp |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
private static getCookieRegExp; |
||||
|
/** |
||||
|
* Gets the unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @param encodedURIComponent A value representing an encoded URI component. |
||||
|
* |
||||
|
* @returns The unencoded version of an encoded component of a Uniform Resource Identifier (URI). |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
private static safeDecodeURIComponent; |
||||
|
/** |
||||
|
* Return `true` if {@link Document} is accessible, otherwise return `false` |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns boolean - whether cookie with specified name exists |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
check(name: string): boolean; |
||||
|
/** |
||||
|
* Get cookies by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @returns property value |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
get(name: string): string; |
||||
|
/** |
||||
|
* Get all cookies in JSON format |
||||
|
* |
||||
|
* @returns all the cookies in json |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
getAll(): { |
||||
|
[key: string]: string; |
||||
|
}; |
||||
|
/** |
||||
|
* Set cookie based on provided information |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @param value Cookie value |
||||
|
* @param expires Number of days until the cookies expires or an actual `Date` |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Secure flag |
||||
|
* @param sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
set(name: string, value: string, expires?: number | Date, path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'None' | 'Strict'): void; |
||||
|
/** |
||||
|
* Set cookie based on provided information |
||||
|
* |
||||
|
* Cookie's parameters: |
||||
|
* <pre> |
||||
|
* expires Number of days until the cookies expires or an actual `Date` |
||||
|
* path Cookie path |
||||
|
* domain Cookie domain |
||||
|
* secure Secure flag |
||||
|
* sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` |
||||
|
* </pre> |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @param value Cookie value |
||||
|
* @param options Body with cookie's params |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
set(name: string, value: string, options?: { |
||||
|
expires?: number | Date; |
||||
|
path?: string; |
||||
|
domain?: string; |
||||
|
secure?: boolean; |
||||
|
sameSite?: 'Lax' | 'None' | 'Strict'; |
||||
|
}): void; |
||||
|
/** |
||||
|
* Delete cookie by name |
||||
|
* |
||||
|
* @param name Cookie name |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Cookie secure flag |
||||
|
* @param sameSite Cookie sameSite flag - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
delete(name: string, path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'None' | 'Strict'): void; |
||||
|
/** |
||||
|
* Delete all cookies |
||||
|
* |
||||
|
* @param path Cookie path |
||||
|
* @param domain Cookie domain |
||||
|
* @param secure Is the Cookie secure |
||||
|
* @param sameSite Is the cookie same site |
||||
|
* |
||||
|
* @author: Stepan Suvorov |
||||
|
* @since: 1.0.0 |
||||
|
*/ |
||||
|
deleteAll(path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'None' | 'Strict'): void; |
||||
|
static ɵfac: i0.ɵɵFactoryDeclaration<CookieService, never>; |
||||
|
static ɵprov: i0.ɵɵInjectableDeclaration<CookieService>; |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
/** |
||||
|
* Generated bundle index. Do not edit. |
||||
|
*/ |
||||
|
/// <amd-module name="ngx-cookie-service" />
|
||||
|
export * from './public-api'; |
@ -0,0 +1,144 @@ |
|||||
|
{ |
||||
|
"_from": "ngx-cookie-service", |
||||
|
"_id": "ngx-cookie-service@13.1.2", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha512-CInzm1xjI51QA1gCJEnqfDFLnN7w/SzqM5+kGdpI+UiCeHKgYEXpKG1s7lFz4jbLDrL/jHKtrf92t7RGsm66Cg==", |
||||
|
"_location": "/ngx-cookie-service", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "tag", |
||||
|
"registry": true, |
||||
|
"raw": "ngx-cookie-service", |
||||
|
"name": "ngx-cookie-service", |
||||
|
"escapedName": "ngx-cookie-service", |
||||
|
"rawSpec": "", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "latest" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"#USER", |
||||
|
"/" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-13.1.2.tgz", |
||||
|
"_shasum": "31dbd523e16765649661e36cb436d8f19bd9ea4b", |
||||
|
"_spec": "ngx-cookie-service", |
||||
|
"_where": "/Users/satish.ganga/Desktop/EKAM/ekamv3/skgangaEkam", |
||||
|
"author": { |
||||
|
"name": "Stepan Suvorov", |
||||
|
"email": "stevermeister@gmail.com" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/stevermeister/ngx-cookie-service/issues", |
||||
|
"email": "stepan@studytube.nl" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"contributors": [ |
||||
|
{ |
||||
|
"name": "Pavan Kumar Jadda" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "Christopher Parotat", |
||||
|
"email": "c.parotat@7leads.org" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "Stefan Bauer", |
||||
|
"email": "bauer.stefan@live.de" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "Kristian Thy", |
||||
|
"email": "thy@42.dk" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "Jared Clemence" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "flakolefluk" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "mattbanks" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "DBaker85" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "Matt Lewis", |
||||
|
"email": "npm@mattlewis.me" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "IceBreakerG" |
||||
|
} |
||||
|
], |
||||
|
"dependencies": { |
||||
|
"tslib": "^2.0.0" |
||||
|
}, |
||||
|
"deprecated": false, |
||||
|
"description": "Angular cookie service", |
||||
|
"es2020": "fesm2020/ngx-cookie-service.mjs", |
||||
|
"esm2020": "esm2020/ngx-cookie-service.mjs", |
||||
|
"exports": { |
||||
|
"./package.json": { |
||||
|
"default": "./package.json" |
||||
|
}, |
||||
|
".": { |
||||
|
"types": "./ngx-cookie-service.d.ts", |
||||
|
"esm2020": "./esm2020/ngx-cookie-service.mjs", |
||||
|
"es2020": "./fesm2020/ngx-cookie-service.mjs", |
||||
|
"es2015": "./fesm2015/ngx-cookie-service.mjs", |
||||
|
"node": "./fesm2015/ngx-cookie-service.mjs", |
||||
|
"default": "./fesm2020/ngx-cookie-service.mjs" |
||||
|
} |
||||
|
}, |
||||
|
"fesm2015": "fesm2015/ngx-cookie-service.mjs", |
||||
|
"fesm2020": "fesm2020/ngx-cookie-service.mjs", |
||||
|
"homepage": "https://github.com/stevermeister/ngx-cookie-service#readme", |
||||
|
"keywords": [ |
||||
|
"angular", |
||||
|
"angular2", |
||||
|
"angular4", |
||||
|
"angular5", |
||||
|
"angular-2", |
||||
|
"angular-4", |
||||
|
"angular-5", |
||||
|
"angular-6", |
||||
|
"angular-7", |
||||
|
"angular-8", |
||||
|
"angular-9", |
||||
|
"angular-10", |
||||
|
"angular-11", |
||||
|
"angular-12", |
||||
|
"angular-13", |
||||
|
"ivy", |
||||
|
"ivy-compatible", |
||||
|
"ivy-compilation", |
||||
|
"ngx", |
||||
|
"ng2", |
||||
|
"ng", |
||||
|
"service", |
||||
|
"angular-service", |
||||
|
"cookie-service", |
||||
|
"cookie", |
||||
|
"cookies" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"module": "fesm2015/ngx-cookie-service.mjs", |
||||
|
"name": "ngx-cookie-service", |
||||
|
"peerDependencies": { |
||||
|
"@angular/common": "^13.0.0", |
||||
|
"@angular/core": "^13.0.0" |
||||
|
}, |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/stevermeister/ngx-cookie-service.git" |
||||
|
}, |
||||
|
"resolve": { |
||||
|
"fallback": { |
||||
|
"path": false, |
||||
|
"http": false, |
||||
|
"stream": false, |
||||
|
"util": false |
||||
|
} |
||||
|
}, |
||||
|
"sideEffects": false, |
||||
|
"typings": "ngx-cookie-service.d.ts", |
||||
|
"version": "13.1.2" |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
export * from './lib/cookie.service'; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue