├── .github
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── documentation.md
│ ├── feature-request.md
│ └── maintenance.md
├── PULL_REQUEST_TEMPLATE.md
├── SUPPORT
└── workflows
│ └── node-test.yml
├── .gitignore
├── .storybook
├── config.js
└── webpack.config.js
├── .travis.yml
├── CNAME
├── LICENSE
├── README.md
├── __tests__
├── __test_utils__.js
├── floodgate.test.js
├── functions.test.js
└── helpers.test.js
├── index.js
├── package.json
├── rollup.config.js
├── src
├── classes.ts
├── functions.tsx
├── helpers.tsx
├── index.tsx
└── types.d.ts
├── stories
├── demos.js
└── index.js
└── tsconfig.json
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @geoffdavis92
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
4 |
5 | For more information please visit the [No Code of Conduct](https://nocodeofconduct.com) homepage.
6 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to react-floodgate
2 |
3 | Welcome! As a contributor to this project, it is expected that you abide by the [Code of Conduct](./CODE_OF_CONDUCT.md).
4 |
5 | ## Setup
6 |
7 | This project uses [Yarn](https://yarnpkg.com) as its package manager; it is highly recommended that contributors use Yarn if possible.
8 |
9 | 1. Fork and clone the repo
10 | 2. Run `yarn` to install dependencies
11 | 3. Create a branch for your PR
12 |
13 | ### Creating a branch
14 |
15 | When creating a branch, please adhere to the following branch name specification:
16 |
17 | `{username}/{branch_name}`
18 |
19 | Where:
20 |
21 | - `{username}`: your Github username
22 | - `{branch_name}`: desdcriptive branch name in camelCase
23 |
24 | This makes it clear 1. who is making the PR and 2. what problem is being solved/feature being added/etc when reviewing PRs on Github.
25 |
26 | ## Creating a Pull Request
27 |
28 | After you have forked the repo and created a feature branch, you can submit a [pull request](https://github.com/geoffdavis92/react-floodgate/pulls) directly to this repo.
29 |
30 | ## Yarn scripts
31 |
32 | Any `yarn`/`npm` scripts run locally-installed CLI binaries, so there is no worry about making sure your global binaries of the tools used are up to date. Note, this project primarily uses `yarn`, which is recommended, so ensuring Yarn is properly installed and up-to-date is important in the development process.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [geoffdavis92] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | # patreon: # Replace with a single Patreon username
5 | # open_collective: # Replace with a single Open Collective username
6 | # ko_fi: # Replace with a single Ko-fi username
7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | # liberapay: # Replace with a single Liberapay username
10 | # issuehunt: # Replace with a single IssueHunt username
11 | # otechie: # Replace with a single Otechie username
12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | - `react` version:
2 | - `react-floodgate` version:
3 | - `node` version:
4 | - `npm` (or `yarn`) version:
5 |
6 | Relevant code or config
7 |
8 | ```javascript
9 |
10 | ```
11 |
12 | What you did:
13 |
14 |
15 |
16 | What happened:
17 |
18 |
19 | Reproduction repository:
20 |
23 |
24 | Problem description:
25 |
26 |
27 |
28 | Suggested solution:
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation.md:
--------------------------------------------------------------------------------
1 | ## Documentation Request
2 |
3 |
4 | ### Description
5 |
6 |
7 | ### Motivation
8 |
9 | ## Project Management
10 |
11 |
16 | Branch: `documentation/`
17 |
22 | Floodgate version bump: ``
23 |
24 |
31 | ## Checklist:
32 | - [ ] Merge into `master`
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ## Feature Request
2 |
3 |
4 | ### Description
5 |
6 |
7 | ### Motivation
8 |
9 |
10 | ### Proposed API
11 |
12 | ```diff
13 | + addition
14 | - subtraction
15 | ```
16 |
17 | ## Project Management
18 |
19 |
24 | Branch: `feature/`
25 |
31 | Floodgate version bump: ``
32 |
39 |
40 |
47 | ## Checklist:
48 | - [ ] Relevant tests written and pass
49 | - [ ] Merge into `master`
50 | - [ ] Dist files built
51 | - [ ] Published to npm
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/maintenance.md:
--------------------------------------------------------------------------------
1 | ## Maintenance Request
2 |
3 |
4 | ### Description
5 |
6 |
7 | ### Motivation
8 |
9 |
10 | ### Affected API
11 |
12 | ```diff
13 | + addition
14 | - subtraction
15 | ```
16 |
17 | ## Project Management
18 |
19 |
24 | Branch: `maintenance/`
25 |
30 | Floodgate version bump: ``
31 |
32 |
39 | ## Checklist:
40 | - [ ] Relevant tests written and pass
41 | - [ ] Merge into `master`
42 | - [ ] Dist files built
43 | - [ ] Published to npm
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What:
2 |
3 |
4 | ### Why:
5 |
6 |
7 | ### How:
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/SUPPORT:
--------------------------------------------------------------------------------
1 | # SUPPORT
2 |
3 | The following is a non-exhaustive list of how to get help with this project:
4 |
5 | * [Tweet at Geoff](https://twitter.com/gdavis92)
--------------------------------------------------------------------------------
/.github/workflows/node-test.yml:
--------------------------------------------------------------------------------
1 | name: Node.js CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [8.x, 10.x, 12.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Use Node.js ${{ matrix.node-version }}
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - run: npm install
21 | - run: npm run build --if-present
22 | - run: npm test
23 | env:
24 | CI: true
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # react-floodgate ignores...
2 | .rpt2_cache/
3 | __tests__/__snapshots__/
4 | archive/
5 | dist/
6 | node_modules/
7 | *log
8 | .DS_Store
9 | .travis.yml.swp
10 | package-lock.json
11 | demo.js
12 | yarn.lock
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | function loadStories() {
4 | require('../stories');
5 | }
6 |
7 | configure(loadStories, module);
8 |
--------------------------------------------------------------------------------
/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 | // you can use this file to add your custom webpack plugins, loaders and anything you like.
2 | // This is just the basic way to add additional webpack configurations.
3 | // For more information refer the docs: https://storybook.js.org/configurations/custom-webpack-config
4 |
5 | // IMPORTANT
6 | // When you add this file, we won't add the default configurations which is similar
7 | // to "React Create App". This only has babel loader to load JavaScript.
8 |
9 | const webpack = require("@storybook/react/node_modules/webpack");
10 |
11 | module.exports = {
12 | plugins: [
13 | // your custom plugins
14 | ],
15 | module: {
16 | rules: [
17 | // add your custom rules.
18 | { test: /\.tsx?$/, use: "ts-loader", exclude: /node_modules/ }
19 | ]
20 | },
21 | resolve: {
22 | alias: {
23 | classes: "../src/classes.ts",
24 | functions: "../src/functions.tsx",
25 | helpers: "../src/helpers.tsx",
26 | floodgate: "../dist/floodgate.esm.js"
27 | }
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 8.9
4 | sudo: enabled
5 | branches:
6 | except:
7 | - /documentation\/.+/
8 | install:
9 | - yarn
10 | script:
11 | - yarn run build
12 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | floodgate.js.org
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Geoff Davis
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Floodgate and it's maintainer [@geoffdavis92](https://github.com/geoffdavis92) stand with the Black community
2 |
3 | If you are financially able, please consider donating to [Black Lives Matter](https://secure.actblue.com/donate/ms_blm_homepage_2019) or any number of metropolitan bail funds ([list in this link](https://bit.ly/bailfundslegalhelp)).
4 |
5 | Open source takes cooperation and expertise from all over the world, from people of all ethnic, racial, and national backgrounds; so does fighting for freedom and against police/state brutality and murder.
6 |
7 | Black. Lives. Matter.
8 |
9 | ---
10 |
11 |
react-floodgate 🌊
12 |
Configurable and flexible "load more" component for React
13 |
14 | ---
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ## The motivation
24 |
25 | I have worked on a few client sites and side projects where serialized data is to be displayed concatenated to a given length, with the ability to load more entries after a respective user interaction.
26 |
27 | This can easily result in a complicated mixture of `Array.splice`-ing, potential data mutation, and overly complicated component methods.
28 |
29 | Surely there can be a more elegant solution?
30 |
31 | ## This solution
32 |
33 | Enter `react-floodgate`; like its namesake, this component allows for the precise and safe control of resources. Using an [ES2015 generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) as the control mechanism and the [function-as-child](http://mxstbr.blog/2017/02/react-children-deepdive/#function-as-a-child) pattern for flexible and developer-controlled rendering, one can load serialized data into `react-floodgate`, render their desired components, and safely and programmatically iterate through the data as needed.
34 |
35 | ## The inspiration
36 |
37 | This project was inspired by [Kent Dodd's](https://twitter.com/kentcdodd) [Downshift](https://github.com/paypal/downshift), [this talk](https://www.youtube.com/watch?v=hEGg-3pIHlE) by [Ryan Florence](https://twitter.com/ryanflorence), and [this blog post](http://mxstbr.blog/2017/02/react-children-deepdive/#function-as-a-child) by [Max Stoiber](https://twitter.com/mxstbr).
38 |
39 | This README file modeled after the [Downshift README](https://github.com/paypal/downshift/blob/master/README.md).
40 |
41 | ## Installation
42 |
43 | You can install the package via [**`npm`**](https://npmjs.org/) or [**`yarn`**](https://yarnpkg.com/):
44 |
45 | `$ yarn add react-floodgate`
46 |
47 | or
48 |
49 | `$ npm i --save react-floodgate`
50 |
51 | ## Usage
52 |
53 | This is a basic example of Floodgate, showcasing an uncontrolled implementation:
54 |
55 | ```javascript
56 | const BasicExample = props => (
57 | console.log(stateAtLoadNext)}
63 | onLoadAll={(stateAtLoadAll) => console.log(stateAtLoadAll)}
64 | onReset={(stateAtReset) => console.log(stateAtReset)}>
65 | {({ items, loadNext, loadAll, reset, loadComplete }) => (
66 |
67 |
68 | {items.map(number =>
{number}
)}
69 |
70 |
71 |
72 | {loadComplete ? : null}
73 |
74 | )}
75 |
76 | )
77 | ```
78 |
79 | Uncontrolled Floodgate components are entirely static, and their state will be complete lost/reset when unmounting and re-mounting. In order to ensure internal state is saved during these scenarios, and in order to create dynamic Floodgate components, Floodgate has to be controlled.
80 |
81 | ### Controlled Floodgate
82 |
83 | The following is a basic example of a controlled Floodgate implementation; this component has a location to save Floodgate state, and uses those values as Floodgate's props. In order to make sure this component does save Floodgate's state, the `onExportState` prop will have to have a function passed to it that saves desired Floodgate state properties to the controlling component's state.
84 |
85 | ```javascript
86 | class FloodgateController extends React.Component {
87 | constructor(props) {
88 | super();
89 | this.state = {
90 | showFloodgate: true,
91 | FGState: {
92 | data: props.data,
93 | initial: 3,
94 | increment: 3
95 | }
96 | };
97 | this.toggle = this.toggle.bind(this);
98 | }
99 | toggle() {
100 | this.setState(prevState => ({
101 | showFloodgate: !prevState.showFloodgate
102 | }));
103 | }
104 | render() {
105 | return (
106 |
132 | );
133 | }
134 | }
135 |
136 | const ControlledFGInstance = ;
137 | ```
138 |
139 | This strategy can also be employed to fetch data to pass into Floodgate's `data` prop, or alongside some settings dialogue to allow end-users control over how this feed behaves.
140 |
141 |
176 |
177 | ## API
178 |
179 | ### `Floodgate` props
180 |
181 | | name | type | default | description |
182 | |------------------------|-------------|--------------|-------------------------------------------------------------------------------------------------------------|
183 | | `data` | Array\ | `null` | The array of items to be processed by `Floodgate`| |
184 | | `initial` | number | `5` | How many items are initially available in the render function| |
185 | | `increment` | number | `5` | How many items are added when calling `loadNext`| |
186 | | `exportStateOnUnmount` | boolean | *(optional)* | Toggle if `exportState` will be called during `componentWillUnmount` |
187 | | `onExportState` | Function | *(optional)* | Function to pass up Floodgate's internal state when `componentWillUnmount` fires or `exportState` is called |
188 | | `onLoadNext` | Function | *(optional)* | Callback function to run after `loadNext`; runs after inline `callback` argument prop |
189 | | `onLoadComplete` | Function | *(optional)* | Callback function to run after `loadComplete`; runs after inline `callback` argument prop |
190 | | `onReset` | Function | *(optional)* | Callback function to run after `reset`; runs after inline `callback` argument prop |
191 |
192 | #### `data`
193 |
194 | *Type:* `Array = null`
195 |
196 | The array of items to be processed by the `Floodgate` internal queue.
197 |
198 | This array will accept any type of element, but it is recommended to either provide elements with a uniform type, or normalize elements before they get consumed by `Floodgate`. This best practice is to safeguard against the possibility of performing side effects on an element in Floodgate's `render` function that are incompatible with a given element's type; e.g. an element with a type of `{ name: 'Jane Doe', email: 'jane@doe.com' }`, but in the `render` function performing `exampleItem.toUpperCase()`.
199 |
200 |
201 |
202 | #### `initial`
203 |
204 | *Type:* `number = 5`
205 |
206 | The length of the first set of items that will be rendered from Floodgate.
207 |
208 |
213 |
214 | #### `increment`
215 |
216 | *Type:* `number = 5`
217 |
218 | The length of subsequent sets of items when calling `loadNext`.
219 |
220 | #### `exportStateOnUnmount`
221 |
222 | *Type:* `boolean = false`
223 |
224 | Flag to configure the calling of `props.onExportState` when Floodgate triggers the `componentWillUnmount` component lifecycle event.
225 |
226 | #### `onExportState`
227 |
228 | *Arguments:* `{ currentIndex: number, renderedItems: any[], allItemsRendered: boolean }`
229 |
230 | Prop callback function that executes when Floodgate triggers the `componentWillUnmount` component lifecycle event, or when the [`exportState`](#exportState) is called from the render prop function. It provides a single object argument that represents a set of internal state properties that can be exported to a different component; this is best used on instances that will be toggled (un)mounted, such as in tabs or a single page application.
231 |
232 | `currentIndex` is a number representing the index of the last item passed through the queue to `state.renderedItems`.
233 |
234 | `renderedItems` is an array of all items that have been passed through the queue from `props.data`.
235 |
236 | `allItemsRendered` a boolean describing if all items have been processed by the queue.
237 |
238 | #### `onLoadNext`
239 |
240 | *Arguments:* [`Floodgate.state`](https://github.com/geoffdavis92/react-floodgate/blob/8f9ffe83aaae987246d12533671a335032e9f6dd/src/types.d.ts#L33-L43)
241 |
242 | Callback property that fires after the `loadNext` method is called. This is executed after `loadNext`'s `callback` method is executed.
243 |
244 | #### `onLoadComplete`
245 |
246 | *Arguments:* [`Floodgate.state`](https://github.com/geoffdavis92/react-floodgate/blob/8f9ffe83aaae987246d12533671a335032e9f6dd/src/types.d.ts#L33-L43)
247 |
248 | Callback property that fires after the `loadComplete` method is called. This is executed after `loadComplete`'s `callback` method is executed.
249 |
250 | #### `onReset`
251 |
252 | *Arguments:* [`Floodgate.state`](https://github.com/geoffdavis92/react-floodgate/blob/8f9ffe83aaae987246d12533671a335032e9f6dd/src/types.d.ts#L33-L43)
253 |
254 | Callback property that fires after the `reset` method is called. This is executed after `reset`'s `callback` method is executed.
255 |
256 |
257 | ### `render` function
258 |
259 | **Note:** the `render` function uses a single object argument to expose the following values/functions. Use the ES2015 destructuring syntax to get the most of this pattern. (see the [Usage](#usage) and [Examples](#examples) sections on how to do this)
260 |
261 | | name | type | default | parameters | description |
262 | |----------------|-------------|---------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
263 | | `items` | Array\ | `null` | n/a | State: the subset of items determined by the `intitial` and `increment` props| |
264 | | `loadComplete` | boolean | `false` | n/a | State: describes if all items have been processed by the `Floodgate` instance| |
265 | | `loadAll` | Function | n/a | `{callback?: Function}` | Action: loads all `items`; `callback` prop in argument fires immediately after invocation| |
266 | | `loadNext` | Function | n/a | `{silent?: boolean, callback?: Function}` | Action: loads the next set of items; `callback` prop in argument fires immediately after invocation, `silent` determinse if `onLoadNext` callback is fired after calling `loadNext`| |
267 | | `reset` | Function | n/a | `{callback?: Function}` | Action: resets the state of the `Floodgate` instance to the initial state; `callback` prop in argument fires immediately after invocation| |
268 | | `exportState` | Function | n/a | `null` | Action: calls the `onExportState` prop callback| |
269 | #### `items`
270 |
271 | *Type:* `Array = null`
272 |
273 | Subset of all elements in the `props.data` array, based on the values of the `initial` and `increment` props.
274 |
275 | Elements of `items` do not have to be rendered at all; for example, `props.data` could be comprised of string manipulation methods, and each member of `items` would then call the respective method on a static value.
276 |
277 | #### `loadComplete`
278 |
279 | *Type:* `boolean = false`
280 |
281 | Describes if all elements of the `props.data` array have been processed by the internal queue and passed to `items`.
282 |
283 | #### `loadAll`
284 |
285 | *Arguments:* `{ suppressWarning?: boolean, callback?: Function } = { suppressWarning: false }`
286 |
287 | Appends all elements currently in the `data` prop to the `items` array. When called, the `render` argument's `loadComplete` property will be set to `true`, and the `currentIndex` state property will be updated to the length of `Floodgate.props.data`.
288 |
289 | The `supressWarning` argument property determines if a warning should be emitted when all items are rendered`.
290 |
291 | The `callback` argument method will be called after `loadAll` has set the component's state; it will have access to this updated Floodgate `state`.
292 |
293 | #### `loadNext`
294 |
295 | *Arguments:* `{ silent?: boolean, callback?: Function } = { silent: false }`
296 |
297 | Appends the next elements in the `data` prop to the `items` array, length equal to the `increment` prop. When called, will update the `currentIndex` state property; if this increment is equal to or exceeds the length of `data`, the `render` argument's `loadComplete` property will be set to `true`.
298 |
299 | The `silent` argument property determines if this call triggers the `onLoadNext` prop callback.
300 |
301 | The `callback` argument method will be called after `loadNext` has set the component's state; it will have access to this updated Floodgate `state`.
302 |
303 | #### `reset`
304 |
305 | *Arguments:* `{ initial?: number, callback?: Function } = {}`
306 |
307 | Resets Floodgate's state to the current instance's `data` and `initial` prop values.
308 |
309 | The `initial` argument property provides the ability to pass in a custom `initial` value to the next rendering after `reset` is called; this is most useful when writing a [controlled Floodgate component](#controlled-floodgate) and the `onExportState` prop is used. For more information on why this is needed, see [pull request #42](https://github.com/geoffdavis92/react-floodgate/pull/42).
310 |
311 | The `callback` argument method will be called after `reset` has set the component's state; it will have access to this updated Floodgate `state`.
312 |
313 | #### `exportState`
314 |
315 | *Arguments:* `n/a`
316 |
317 | Calls the `onExportState` prop callback. Any logic to manipulate and/or save Floodgate's state to a parent component should happen in that prop; since the `onExportState` arguments are not configurable, there are no arguments for `exportState`.
318 |
319 | ### Using `FloodgateContext`
320 |
321 | Starting in `v0.6.0`, Floodgate provides a named export `FloodgateContext` that affords the use of the [React Context API](https://reactjs.org/docs/context.html).
322 |
323 | The `FloodgateContext`'s `Consumer` component exposes the same object argument as the [`Floodgate#render` function](#render-function).
324 |
325 | #### Usage
326 |
327 | This `FloodgateContext` object can be used anywhere in the render prop function of a `Floodgate` instance.
328 |
329 | First, define a component that uses the `Consumer` component:
330 | ```javascript
331 | // DeepChildControls.js
332 | import { FloodgateContext } from "react-floodgate";
333 |
334 | const DeepChildControls = (props) => {
335 | return (
336 |