Commit 9d6f1aee authored by Shen Chang's avatar Shen Chang

docs(README): change logo

parent 70d809c2
<p align="center">
<a href="https://github.com/Sam618/react-keep-alive">
<img width="120" src="./assets/logo.svg">
<img width="120" src="https://github.com/Sam618/react-keep-alive/raw/master/assets/logo.png">
</a>
</p>
......
<p align="center">
<a href="https://github.com/Sam618/react-keep-alive">
<img width="120" src="./assets/logo.svg">
</a>
</p>
<h1 align="center">React Keep Alive</h1>
<div align="center">
[![npm](https://img.shields.io/npm/v/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![Travis (.org)](https://img.shields.io/travis/Sam618/react-keep-alive.svg?style=for-the-badge)](https://travis-ci.org/Sam618/react-keep-alive.svg?branch=master) [![license](https://img.shields.io/npm/l/react-keep-alive.svg?style=for-the-badge)](https://github.com/Sam618/react-keep-alive/blob/master/LICENSE) [![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![downloads](https://img.shields.io/npm/dm/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![typescript](https://img.shields.io/badge/language-typescript-blue.svg?style=for-the-badge)](https://www.typescriptlang.org/)
<p>一个保持组件状态并避免重复重渲染的组件。</p>
<div style="width: 100px; text-align: left;">
<div><a href="./README.md">English</a> | 中文</div>
<div><a href="./ONLINE_EDITOR.md">Online Editor</a></div>
</div>
</div>
## 安装
React Keep Alive 最低支持 React 16.3 版本。
在你的应用中安装 React Keep Alive:
```bash
npm install --save react-keep-alive
```
## 使用
React Keep Alive 提供了 `<Provider>`, 你必须把 `<KeepAlive>` 放在 `Provider` 里面。
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
import Test from './views/Test';
ReactDOM.render(
<Provider>
<KeepAlive key="Test">
<Test />
</KeepAlive>
</Provider>,
document.getElementById('root'),
);
```
## 为什么使用这个组件?
如果你用过 [Vue](https://vuejs.org/),那肯定知道它有一个非常好用的组件([keep-alive](https://vuejs.org/v2/guide/components-dynamic-async.html))能够保持组件的状态来避免重复重渲染。
有时,我们希望在列表页面进入详情页面后,缓存列表页面的状态;当从详情页面返回列表页面时,列表页面还是和切换前一样。
这实际上挺难实现的,因为 React 中的组件一旦卸载就无法重用。在 [issue #12039](https://github.com/facebook/react/issues/12039) 中提出了两种解决方案;通过样式来控制组件的显示(`display:none | block;`),但是这可能会导致问题,例如切换组件时,无法使用动画;或者使用像 Mobx 和 Redux 这样的数据流管理工具,但这太麻烦了。
最后,我通过 [React.createPortal API](https://reactjs.org/docs/portals.html) 实现了这个效果。`react-keep-alive` 有两个主要的组件 `<Provider>``<KeepAlive>``<Provider>` 负责保存组件的缓存,并在处理之前通过 `React.createPortal` API 将缓存的组件渲染在应用程序的外面。缓存的组件必须放在 `<KeepAlive>` 中,`<KeepAlive>` 会把在应用程序外面渲染的组件挂载到真正需要显示的位置。
## API 参考
### `Provider`
因为需要存储缓存的组件,所以必须把 `<Provider>` 放在应用程序的最外面以使程序能够正常运行。
#### Props
`include`:只会缓存匹配 `key` 的组件。它可以是字符串,字符串数组或正则表达式,例如:
```JavaScript
<Provider include="A,B">...</Provider>
// or
<Provider include={['A', 'B']}>...</Provider>
// or
<Provider include={/A|B/}>...</Provider>
```
`exclude`:任何匹配 `key` 的组件都不会被缓存。它可以是字符串,字符串数组或正则表达式,例如:
#### 例子
在下面的示例中,`<App />` 是我们的根组件,这意味着它位于组件层次结构的最顶层。
```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-keep-alive';
import App from './App';
ReactDOM.render(
<Provider>
<App />
</Provider>,
document.getElementById('root'),
);
```
##### 结合 React Router 和 Mobx React 使用
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
} from 'react-router-dom';
import {
Provider as MobxProvider,
} from 'mobx-react';
import {
Provider as KeepAliveProvider,
} from 'react-keep-alive';
ReactDOM.render(
<MobxProvider>
<Router>
<KeepAliveProvider>
<App />
</KeepAliveProvider>
</Router>
</MobxProvider>,
document.getElementById('root'),
);
```
**注意**:你必须将 `<Provider>` 放在 `<Router>` 中,并且 React Router 必须确保是 **最新版本**。因为 React Keep Alive 使用了 **new Context**,所以必须确保 `<Router>` 使用相同的 API。请使用以下命令安装 React Router 的最新版本:
```bash
npm install react-router@next react-router-dom@next
```
### `KeepAlive`
我们必须确保 `<KeepAlive>``<Provider>` 里面,这样 `<KeepAlive>` 的子组件才能被缓存。
#### Props
`key``key` 必须存在并且需要确保当前 `<Provider>` 下的所有 `<KeepAlive>``key` 都是唯一的。
`disabled`:当我们不需要缓存组件时,我们可以禁用它;禁用仅在组件从未激活状态变为激活状态时生效。
`onActivate`:激活事件。
`onUnactivate`:未激活事件。
#### 例子
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from 'react-router-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
class One extends React.Component {
render() {
return (
<div>This is One.</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Switch>
<Route path="/one">
<KeepAlive key="One">
<One />
</KeepAlive>
</Route>
</Switch>
</div>
);
}
}
ReactDOM.render(
<Router>
<Provider>
<App />
</Provider>
</Router>,
document.getElementById('root'),
);
```
##### 使用 `<Provider>` 的 `include` 属性
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from 'react-router-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
class One extends React.Component {
render() {
return (
<div>This is One.</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Switch>
<Route path="/one">
<KeepAlive key="One">
<One />
</KeepAlive>
</Route>
</Switch>
</div>
);
}
}
ReactDOM.render(
<Router>
<Provider include="One">
<App />
</Provider>
</Router>,
document.getElementById('root'),
);
```
**注意**:如果要使用 **生命周期**,请将组件包装在 `bindLifecycle` 高阶组件中。
### `bindLifecycle`
这个高阶组件包装的组件将具有 **正确的** 的生命周期,并且我们添加了两个额外的生命周期 `componentDidActivate``componentWillUnactivate`
添加新的生命周期之后:
![Lifecycle after adding](https://github.com/Sam618/react-keep-alive/raw/master/assets/lifecycle.png)
`componentDidActivate` 将在组件刚挂载或从未激活状态变为激活状态时执行。虽然我们在 `Updating` 阶段的 `componentDidUpdate` 之后能够看到 `componentDidActivate`,但这并不意味着 `componentDidActivate` 总是被触发。
同时只能触发 `componentWillUnactivate``componentWillUnmount` 生命周期的其中之一。当需要缓存时执行 `componentWillUnactivate`,而 `componentWillUnmount` 在禁用缓存的情况下执行。
#### 例子
```JavaScript
import React from 'react';
import {bindLifecycle} from 'react-keep-alive';
@bindLifecycle
class Test extends React.Component {
render() {
return (
<div>
This is Test.
</div>
);
}
}
```
## Issues
如果你发现了错误,请在 [我们 GitHub 的 Issues](https://github.com/Sam618/react-keep-alive/issues) 上提出问题。
## Changelog
[CHANGELOG.md](https://github.com/Sam618/react-keep-alive/blob/master/CHANGELOG.md) 中能够查看到所有的更新.
## License
React Keep Alive 使用了 [MIT](https://github.com/Sam618/react-keep-alive/blob/master/LICENSE) 许可.
<p align="center">
<a href="https://github.com/Sam618/react-keep-alive">
<img width="120" src="https://github.com/Sam618/react-keep-alive/raw/master/assets/logo.png">
</a>
</p>
<h1 align="center">React Keep Alive</h1>
<div align="center">
[![npm](https://img.shields.io/npm/v/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![Travis (.org)](https://img.shields.io/travis/Sam618/react-keep-alive.svg?style=for-the-badge)](https://travis-ci.org/Sam618/react-keep-alive.svg?branch=master) [![license](https://img.shields.io/npm/l/react-keep-alive.svg?style=for-the-badge)](https://github.com/Sam618/react-keep-alive/blob/master/LICENSE) [![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![downloads](https://img.shields.io/npm/dm/react-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-keep-alive) [![typescript](https://img.shields.io/badge/language-typescript-blue.svg?style=for-the-badge)](https://www.typescriptlang.org/)
<p>一个保持组件状态并避免重复重渲染的组件。</p>
<div style="width: 100px; text-align: left;">
<div><a href="./README.md">English</a> | 中文</div>
<div><a href="./ONLINE_EDITOR.md">Online Editor</a></div>
</div>
</div>
## 安装
React Keep Alive 最低支持 React 16.3 版本。
在你的应用中安装 React Keep Alive:
```bash
npm install --save react-keep-alive
```
## 使用
React Keep Alive 提供了 `<Provider>`, 你必须把 `<KeepAlive>` 放在 `Provider` 里面。
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
import Test from './views/Test';
ReactDOM.render(
<Provider>
<KeepAlive key="Test">
<Test />
</KeepAlive>
</Provider>,
document.getElementById('root'),
);
```
## 为什么使用这个组件?
如果你用过 [Vue](https://vuejs.org/),那肯定知道它有一个非常好用的组件([keep-alive](https://vuejs.org/v2/guide/components-dynamic-async.html))能够保持组件的状态来避免重复重渲染。
有时,我们希望在列表页面进入详情页面后,缓存列表页面的状态;当从详情页面返回列表页面时,列表页面还是和切换前一样。
这实际上挺难实现的,因为 React 中的组件一旦卸载就无法重用。在 [issue #12039](https://github.com/facebook/react/issues/12039) 中提出了两种解决方案;通过样式来控制组件的显示(`display:none | block;`),但是这可能会导致问题,例如切换组件时,无法使用动画;或者使用像 Mobx 和 Redux 这样的数据流管理工具,但这太麻烦了。
最后,我通过 [React.createPortal API](https://reactjs.org/docs/portals.html) 实现了这个效果。`react-keep-alive` 有两个主要的组件 `<Provider>``<KeepAlive>``<Provider>` 负责保存组件的缓存,并在处理之前通过 `React.createPortal` API 将缓存的组件渲染在应用程序的外面。缓存的组件必须放在 `<KeepAlive>` 中,`<KeepAlive>` 会把在应用程序外面渲染的组件挂载到真正需要显示的位置。
## API 参考
### `Provider`
因为需要存储缓存的组件,所以必须把 `<Provider>` 放在应用程序的最外面以使程序能够正常运行。
#### Props
`include`:只会缓存匹配 `key` 的组件。它可以是字符串,字符串数组或正则表达式,例如:
```JavaScript
<Provider include="A,B">...</Provider>
// or
<Provider include={['A', 'B']}>...</Provider>
// or
<Provider include={/A|B/}>...</Provider>
```
`exclude`:任何匹配 `key` 的组件都不会被缓存。它可以是字符串,字符串数组或正则表达式,例如:
#### 例子
在下面的示例中,`<App />` 是我们的根组件,这意味着它位于组件层次结构的最顶层。
```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-keep-alive';
import App from './App';
ReactDOM.render(
<Provider>
<App />
</Provider>,
document.getElementById('root'),
);
```
##### 结合 React Router 和 Mobx React 使用
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
} from 'react-router-dom';
import {
Provider as MobxProvider,
} from 'mobx-react';
import {
Provider as KeepAliveProvider,
} from 'react-keep-alive';
ReactDOM.render(
<MobxProvider>
<Router>
<KeepAliveProvider>
<App />
</KeepAliveProvider>
</Router>
</MobxProvider>,
document.getElementById('root'),
);
```
**注意**:你必须将 `<Provider>` 放在 `<Router>` 中,并且 React Router 必须确保是 **最新版本**。因为 React Keep Alive 使用了 **new Context**,所以必须确保 `<Router>` 使用相同的 API。请使用以下命令安装 React Router 的最新版本:
```bash
npm install react-router@next react-router-dom@next
```
### `KeepAlive`
我们必须确保 `<KeepAlive>``<Provider>` 里面,这样 `<KeepAlive>` 的子组件才能被缓存。
#### Props
`key``key` 必须存在并且需要确保当前 `<Provider>` 下的所有 `<KeepAlive>``key` 都是唯一的。
`disabled`:当我们不需要缓存组件时,我们可以禁用它;禁用仅在组件从未激活状态变为激活状态时生效。
`onActivate`:激活事件。
`onUnactivate`:未激活事件。
#### 例子
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from 'react-router-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
class One extends React.Component {
render() {
return (
<div>This is One.</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Switch>
<Route path="/one">
<KeepAlive key="One">
<One />
</KeepAlive>
</Route>
</Switch>
</div>
);
}
}
ReactDOM.render(
<Router>
<Provider>
<App />
</Provider>
</Router>,
document.getElementById('root'),
);
```
##### 使用 `<Provider>` 的 `include` 属性
```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from 'react-router-dom';
import {
Provider,
KeepAlive,
} from 'react-keep-alive';
class One extends React.Component {
render() {
return (
<div>This is One.</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Switch>
<Route path="/one">
<KeepAlive key="One">
<One />
</KeepAlive>
</Route>
</Switch>
</div>
);
}
}
ReactDOM.render(
<Router>
<Provider include="One">
<App />
</Provider>
</Router>,
document.getElementById('root'),
);
```
**注意**:如果要使用 **生命周期**,请将组件包装在 `bindLifecycle` 高阶组件中。
### `bindLifecycle`
这个高阶组件包装的组件将具有 **正确的** 的生命周期,并且我们添加了两个额外的生命周期 `componentDidActivate``componentWillUnactivate`
添加新的生命周期之后:
![Lifecycle after adding](https://github.com/Sam618/react-keep-alive/raw/master/assets/lifecycle.png)
`componentDidActivate` 将在组件刚挂载或从未激活状态变为激活状态时执行。虽然我们在 `Updating` 阶段的 `componentDidUpdate` 之后能够看到 `componentDidActivate`,但这并不意味着 `componentDidActivate` 总是被触发。
同时只能触发 `componentWillUnactivate``componentWillUnmount` 生命周期的其中之一。当需要缓存时执行 `componentWillUnactivate`,而 `componentWillUnmount` 在禁用缓存的情况下执行。
#### 例子
```JavaScript
import React from 'react';
import {bindLifecycle} from 'react-keep-alive';
@bindLifecycle
class Test extends React.Component {
render() {
return (
<div>
This is Test.
</div>
);
}
}
```
## Issues
如果你发现了错误,请在 [我们 GitHub 的 Issues](https://github.com/Sam618/react-keep-alive/issues) 上提出问题。
## Changelog
[CHANGELOG.md](https://github.com/Sam618/react-keep-alive/blob/master/CHANGELOG.md) 中能够查看到所有的更新.
## License
React Keep Alive 使用了 [MIT](https://github.com/Sam618/react-keep-alive/blob/master/LICENSE) 许可.
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1552810005619" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7010" data-spm-anchor-id="a313x.7781069.0.i17" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M1024.213333 510.186667c0-67.733333-84.8-131.946667-214.933333-171.733334C839.253333 205.866667 825.92 100.373333 767.146667 66.56c-13.546667-7.893333-29.44-11.626667-46.72-11.626667v46.506667c9.6 0 17.28 1.92 23.786666 5.44 28.373333 16.213333 40.64 78.186667 31.04 157.76-2.24 19.626667-6.08 40.213333-10.666666 61.333333-40.853333-10.026667-85.44-17.706667-132.373334-22.72-28.16-38.613333-57.28-73.6-86.72-104.213333 67.946667-63.146667 131.733333-97.813333 175.146667-97.813333V54.72c-57.28 0-132.373333 40.853333-208.213333 111.786667-75.84-70.506667-150.933333-110.933333-208.213334-110.933334v46.506667c43.2 0 107.2 34.346667 175.146667 97.173333-29.226667 30.613333-58.346667 65.493333-86.08 104-47.146667 5.013333-91.733333 12.693333-132.586667 22.933334-4.8-20.8-8.32-41.066667-10.88-60.48-9.813333-79.68 2.24-141.546667 30.4-157.973334 6.293333-3.733333 14.4-5.44 24-5.44V55.786667c-17.493333 0-33.386667 3.733333-47.146666 11.626666-58.56 33.813333-71.68 139.093333-41.493334 271.253334C85.866667 378.666667 1.493333 442.666667 1.493333 510.186667c0 67.733333 84.8 131.946667 214.933334 171.733333-29.973333 132.586667-16.64 238.08 42.133333 271.786667 13.546667 7.893333 29.44 11.626667 46.933333 11.626666 57.28 0 132.373333-40.853333 208.213334-111.786666 75.84 70.506667 150.933333 110.933333 208.213333 110.933333 17.493333 0 33.386667-3.733333 47.146667-11.626667 58.56-33.813333 71.68-139.093333 41.493333-271.253333 129.173333-39.68 213.653333-103.893333 213.653333-171.413333zM752.746667 371.2c-7.68 26.88-17.28 54.613333-28.16 82.346667-8.533333-16.64-17.493333-33.386667-27.306667-50.026667-9.6-16.64-19.84-32.96-29.973333-48.746667 29.653333 4.266667 58.133333 9.706667 85.44 16.426667z m-95.466667 221.973333c-16.213333 28.16-32.96 54.826667-50.24 79.68-31.04 2.666667-62.506667 4.16-94.186667 4.16-31.466667 0-62.933333-1.493333-93.76-3.946666-17.28-24.853333-34.24-51.306667-50.453333-79.253334-15.893333-27.306667-30.186667-55.04-43.413333-82.986666 12.906667-27.946667 27.52-55.893333 43.2-83.2 16.213333-28.16 32.96-54.826667 50.24-79.68 31.04-2.666667 62.506667-4.16 94.186666-4.16 31.466667 0 62.933333 1.493333 93.76 3.946666 17.28 24.853333 34.24 51.306667 50.453334 79.253334 15.893333 27.306667 30.186667 55.04 43.413333 82.986666-13.12 27.946667-27.52 55.893333-43.2 83.2z m67.413333-27.093333c11.306667 27.946667 20.8 55.893333 28.8 82.986667-27.306667 6.72-56.106667 12.266667-85.866666 16.64 10.24-16 20.48-32.533333 29.973333-49.386667 9.493333-16.64 18.453333-33.6 27.093333-50.24zM513.28 788.48c-19.413333-20.053333-38.826667-42.346667-57.92-66.666667 18.773333 0.853333 37.973333 1.493333 57.28 1.493334 19.626667 0 38.933333-0.426667 57.92-1.493334-18.773333 24.32-38.08 46.72-57.28 66.666667zM358.186667 665.706667c-29.653333-4.373333-58.133333-9.813333-85.44-16.426667 7.68-26.88 17.28-54.613333 28.16-82.346667 8.533333 16.64 17.493333 33.386667 27.306666 50.026667 9.706667 16.64 19.733333 32.96 29.973334 48.746667z m154.026666-433.813334c19.413333 20.053333 38.826667 42.346667 57.92 66.666667-18.773333-0.853333-37.973333-1.493333-57.28-1.493333-19.626667 0-38.933333 0.426667-57.92 1.493333 18.773333-24.32 38.08-46.613333 57.28-66.666667zM357.973333 354.666667c-10.24 16-20.48 32.533333-29.973333 49.386666-9.6 16.64-18.56 33.386667-27.093333 50.026667-11.306667-27.946667-20.8-55.893333-28.8-82.986667 27.306667-6.4 56-12.053333 85.866666-16.426666zM169.28 615.68C95.466667 584.213333 47.786667 542.933333 47.786667 510.186667s47.786667-74.24 121.493333-105.493334c17.92-7.68 37.546667-14.613333 57.706667-21.013333 11.84 40.853333 27.52 83.413333 46.933333 126.933333-19.2 43.413333-34.56 85.653333-46.293333 126.293334-20.586667-6.4-40.213333-13.546667-58.346667-21.226667z m112.213333 297.92c-28.373333-16.213333-40.64-78.186667-31.04-157.76 2.24-19.626667 6.08-40.213333 10.666667-61.333333 40.853333 10.026667 85.44 17.706667 132.373333 22.72 28.16 38.613333 57.28 73.6 86.72 104.213333-67.946667 63.146667-131.733333 97.813333-175.146666 97.813333-9.386667-0.213333-17.386667-2.133333-23.573334-5.653333z m494.4-158.826667c9.813333 79.68-2.24 141.546667-30.4 157.973334-6.293333 3.733333-14.4 5.44-24 5.44-43.2 0-107.2-34.346667-175.146666-97.173334 29.226667-30.613333 58.346667-65.493333 86.08-104 47.146667-5.013333 91.733333-12.693333 132.586666-22.933333 4.906667 21.013333 8.64 41.28 10.88 60.693333z m80.32-139.093333c-17.92 7.68-37.546667 14.613333-57.706666 21.013333-11.84-40.853333-27.52-83.413333-46.933334-126.933333 19.2-43.413333 34.56-85.653333 46.293334-126.293333 20.586667 6.506667 40.213333 13.546667 58.56 21.226666 73.813333 31.466667 121.493333 72.746667 121.493333 105.493334-0.213333 32.746667-47.893333 74.24-121.706667 105.493333zM304 55.573333z" fill="#d81e06" p-id="7011" data-spm-anchor-id="a313x.7781069.0.i15" class=""></path><path d="M512.64 510.186667m-95.253333 0a95.253333 95.253333 0 1 0 190.506666 0 95.253333 95.253333 0 1 0-190.506666 0Z" fill="#1296db" p-id="7012" data-spm-anchor-id="a313x.7781069.0.i14" class="selected"></path><path d="M720.32 54.933333z" fill="#05A5D1" p-id="7013"></path></svg>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment