redux-router5
Advanced tools
Comparing version 4.1.0 to 4.2.0
@@ -0,1 +1,11 @@ | ||
<a name="4.2.0"></a> | ||
# 4.2.0 (2016-09-13) | ||
### Features | ||
* add immutable-js support in routeNodeSelector and immutable-js reducer ([8764ce6](https://github.com/router5/redux-router5/commit/8764ce6)) | ||
<a name="4.1.0"></a> | ||
@@ -2,0 +12,0 @@ # [4.1.0](https://github.com/router5/redux-router5/compare/v4.0.0...v4.1.0) (2016-09-13) |
@@ -7,3 +7,3 @@ import transitionPath from 'router5.transition-path'; | ||
var routerStateSelector = function routerStateSelector(state) { | ||
return state[reducerKey]; | ||
return state[reducerKey] || state.get && state.get(reducerKey); | ||
}; | ||
@@ -10,0 +10,0 @@ var lastReturnedValue = void 0; |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define('reduxRouter5', ['exports'], factory) : | ||
(factory((global.reduxRouter5 = global.reduxRouter5 || {}))); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define('reduxRouter5', ['exports'], factory) : | ||
(factory((global.reduxRouter5 = global.reduxRouter5 || {}))); | ||
}(this, function (exports) { 'use strict'; | ||
var babelHelpers = {}; | ||
babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; | ||
}; | ||
var NAVIGATE_TO = '@@router5/NAVIGATE'; | ||
var CANCEL_TRANSITION = '@@router5/CANCEL'; | ||
var TRANSITION_ERROR = '@@router5/TRANSITION_ERROR'; | ||
var TRANSITION_SUCCESS = '@@router5/TRANSITION_SUCCESS'; | ||
var TRANSITION_START = '@@router5/TRANSITION_START'; | ||
var CLEAR_ERRORS = '@@router5/CLEAR_ERRORS'; | ||
var CAN_DEACTIVATE = '@@router5/CAN_DEACTIVATE'; | ||
var CAN_ACTIVATE = '@@router5/CAN_ACTIVATE'; | ||
babelHelpers.extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
var actionTypes = Object.freeze({ | ||
NAVIGATE_TO: NAVIGATE_TO, | ||
CANCEL_TRANSITION: CANCEL_TRANSITION, | ||
TRANSITION_ERROR: TRANSITION_ERROR, | ||
TRANSITION_SUCCESS: TRANSITION_SUCCESS, | ||
TRANSITION_START: TRANSITION_START, | ||
CLEAR_ERRORS: CLEAR_ERRORS, | ||
CAN_DEACTIVATE: CAN_DEACTIVATE, | ||
CAN_ACTIVATE: CAN_ACTIVATE | ||
}); | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
function navigateTo(name) { | ||
var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var opts = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
return { | ||
type: NAVIGATE_TO, | ||
payload: { | ||
name: name, | ||
params: params, | ||
opts: opts | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
return target; | ||
}; | ||
function cancelTransition() { | ||
return { | ||
type: CANCEL_TRANSITION | ||
}; | ||
} | ||
babelHelpers; | ||
function clearErrors() { | ||
return { | ||
type: CLEAR_ERRORS | ||
}; | ||
} | ||
var NAVIGATE_TO = '@@router5/NAVIGATE'; | ||
var CANCEL_TRANSITION = '@@router5/CANCEL'; | ||
var TRANSITION_ERROR = '@@router5/TRANSITION_ERROR'; | ||
var TRANSITION_SUCCESS = '@@router5/TRANSITION_SUCCESS'; | ||
var TRANSITION_START = '@@router5/TRANSITION_START'; | ||
var CLEAR_ERRORS = '@@router5/CLEAR_ERRORS'; | ||
var CAN_DEACTIVATE = '@@router5/CAN_DEACTIVATE'; | ||
var CAN_ACTIVATE = '@@router5/CAN_ACTIVATE'; | ||
function transitionStart(route, previousRoute) { | ||
return { | ||
type: TRANSITION_START, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute | ||
} | ||
}; | ||
} | ||
var actionTypes = Object.freeze({ | ||
NAVIGATE_TO: NAVIGATE_TO, | ||
CANCEL_TRANSITION: CANCEL_TRANSITION, | ||
TRANSITION_ERROR: TRANSITION_ERROR, | ||
TRANSITION_SUCCESS: TRANSITION_SUCCESS, | ||
TRANSITION_START: TRANSITION_START, | ||
CLEAR_ERRORS: CLEAR_ERRORS, | ||
CAN_DEACTIVATE: CAN_DEACTIVATE, | ||
CAN_ACTIVATE: CAN_ACTIVATE | ||
}); | ||
function transitionSuccess(route, previousRoute) { | ||
return { | ||
type: TRANSITION_SUCCESS, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute | ||
} | ||
}; | ||
} | ||
function navigateTo(name) { | ||
var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var opts = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; | ||
function transitionError(route, previousRoute, transitionError) { | ||
return { | ||
type: TRANSITION_ERROR, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute, | ||
transitionError: transitionError | ||
} | ||
}; | ||
} | ||
return { | ||
type: NAVIGATE_TO, | ||
payload: { | ||
name: name, | ||
params: params, | ||
opts: opts | ||
} | ||
}; | ||
} | ||
function canActivate(name, canActivate) { | ||
return { | ||
type: CAN_ACTIVATE, | ||
payload: { | ||
name: name, | ||
canActivate: canActivate | ||
} | ||
}; | ||
} | ||
function cancelTransition() { | ||
return { | ||
type: CANCEL_TRANSITION | ||
}; | ||
} | ||
function canDeactivate(name, canDeactivate) { | ||
return { | ||
type: CAN_DEACTIVATE, | ||
payload: { | ||
name: name, | ||
canDeactivate: canDeactivate | ||
} | ||
}; | ||
} | ||
function clearErrors() { | ||
return { | ||
type: CLEAR_ERRORS | ||
}; | ||
} | ||
var actions = Object.freeze({ | ||
navigateTo: navigateTo, | ||
cancelTransition: cancelTransition, | ||
clearErrors: clearErrors, | ||
transitionStart: transitionStart, | ||
transitionSuccess: transitionSuccess, | ||
transitionError: transitionError, | ||
canActivate: canActivate, | ||
canDeactivate: canDeactivate | ||
}); | ||
function transitionStart(route, previousRoute) { | ||
return { | ||
type: TRANSITION_START, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute | ||
} | ||
}; | ||
} | ||
function reduxPluginFactory(dispatch) { | ||
function reduxPlugin() { | ||
return { | ||
onTransitionStart: function onTransitionStart(toState, fromState) { | ||
dispatch(transitionStart(toState, fromState)); | ||
}, | ||
onTransitionSuccess: function onTransitionSuccess(toState, fromState) { | ||
dispatch(transitionSuccess(toState, fromState)); | ||
}, | ||
onTransitionError: function onTransitionError(toState, fromState, err) { | ||
dispatch(transitionError(toState, fromState, err)); | ||
} | ||
}; | ||
}; | ||
function transitionSuccess(route, previousRoute) { | ||
return { | ||
type: TRANSITION_SUCCESS, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute | ||
} | ||
}; | ||
} | ||
reduxPlugin.pluginName = 'REDUX_PLUGIN'; | ||
function transitionError(route, previousRoute, transitionError) { | ||
return { | ||
type: TRANSITION_ERROR, | ||
payload: { | ||
route: route, | ||
previousRoute: previousRoute, | ||
transitionError: transitionError | ||
} | ||
}; | ||
} | ||
return reduxPlugin; | ||
} | ||
function canActivate(name, canActivate) { | ||
return { | ||
type: CAN_ACTIVATE, | ||
payload: { | ||
name: name, | ||
canActivate: canActivate | ||
} | ||
}; | ||
} | ||
var router5ReduxMiddleware = function router5ReduxMiddleware(router) { | ||
return function (store) { | ||
var dispatch = store.dispatch; | ||
function canDeactivate(name, canDeactivate) { | ||
return { | ||
type: CAN_DEACTIVATE, | ||
payload: { | ||
name: name, | ||
canDeactivate: canDeactivate | ||
} | ||
}; | ||
} | ||
router.setDependency('store', store); | ||
router.usePlugin(reduxPluginFactory(dispatch)); | ||
var actions = Object.freeze({ | ||
navigateTo: navigateTo, | ||
cancelTransition: cancelTransition, | ||
clearErrors: clearErrors, | ||
transitionStart: transitionStart, | ||
transitionSuccess: transitionSuccess, | ||
transitionError: transitionError, | ||
canActivate: canActivate, | ||
canDeactivate: canDeactivate | ||
}); | ||
return function (next) { | ||
return function (action) { | ||
switch (action.type) { | ||
case NAVIGATE_TO: | ||
var _action$payload = action.payload; | ||
var name = _action$payload.name; | ||
var params = _action$payload.params; | ||
var opts = _action$payload.opts; | ||
function reduxPluginFactory(dispatch) { | ||
function reduxPlugin() { | ||
return { | ||
onTransitionStart: function onTransitionStart(toState, fromState) { | ||
dispatch(transitionStart(toState, fromState)); | ||
}, | ||
onTransitionSuccess: function onTransitionSuccess(toState, fromState) { | ||
dispatch(transitionSuccess(toState, fromState)); | ||
}, | ||
onTransitionError: function onTransitionError(toState, fromState, err) { | ||
dispatch(transitionError(toState, fromState, err)); | ||
} | ||
}; | ||
}; | ||
router.navigate(name, params, opts); | ||
break; | ||
reduxPlugin.pluginName = 'REDUX_PLUGIN'; | ||
case CANCEL_TRANSITION: | ||
router.cancel(); | ||
break; | ||
return reduxPlugin; | ||
} | ||
case CAN_DEACTIVATE: | ||
router.canDeactivate(action.payload.name, action.payload.canDeactivate); | ||
break; | ||
var router5ReduxMiddleware = function router5ReduxMiddleware(router) { | ||
return function (store) { | ||
var dispatch = store.dispatch; | ||
case CAN_ACTIVATE: | ||
router.canActivate(action.payload.name, action.payload.canDeactivate); | ||
break; | ||
router.setDependency('store', store); | ||
router.usePlugin(reduxPluginFactory(dispatch)); | ||
default: | ||
return next(action); | ||
} | ||
}; | ||
}; | ||
}; | ||
}; | ||
return function (next) { | ||
return function (action) { | ||
switch (action.type) { | ||
case NAVIGATE_TO: | ||
var _action$payload = action.payload; | ||
var name = _action$payload.name; | ||
var params = _action$payload.params; | ||
var opts = _action$payload.opts; | ||
var typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; | ||
}; | ||
router.navigate(name, params, opts); | ||
break; | ||
var _extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
case CANCEL_TRANSITION: | ||
router.cancel(); | ||
break; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
case CAN_DEACTIVATE: | ||
router.canDeactivate(action.payload.name, action.payload.canDeactivate); | ||
break; | ||
return target; | ||
}; | ||
case CAN_ACTIVATE: | ||
router.canActivate(action.payload.name, action.payload.canDeactivate); | ||
break; | ||
var initialState = { | ||
route: null, | ||
previousRoute: null, | ||
transitionRoute: null, | ||
transitionError: null | ||
}; | ||
default: | ||
return next(action); | ||
} | ||
}; | ||
}; | ||
}; | ||
}; | ||
function router5Reducer() { | ||
var state = arguments.length <= 0 || arguments[0] === undefined ? initialState : arguments[0]; | ||
var action = arguments[1]; | ||
var initialState = { | ||
route: null, | ||
previousRoute: null, | ||
transitionRoute: null, | ||
transitionError: null | ||
}; | ||
switch (action.type) { | ||
case TRANSITION_START: | ||
return _extends({}, state, { | ||
transitionRoute: action.payload.route, | ||
transitionError: null | ||
}); | ||
function router5Reducer() { | ||
var state = arguments.length <= 0 || arguments[0] === undefined ? initialState : arguments[0]; | ||
var action = arguments[1]; | ||
case TRANSITION_SUCCESS: | ||
return _extends({}, state, { | ||
transitionRoute: null, | ||
transitionError: null, | ||
previousRoute: action.payload.previousRoute, | ||
route: action.payload.route | ||
}); | ||
switch (action.type) { | ||
case TRANSITION_START: | ||
return babelHelpers.extends({}, state, { | ||
transitionRoute: action.payload.route, | ||
transitionError: null | ||
}); | ||
case TRANSITION_ERROR: | ||
return _extends({}, state, { | ||
transitionRoute: action.payload.route, | ||
transitionError: action.payload.transitionError | ||
}); | ||
case TRANSITION_SUCCESS: | ||
return babelHelpers.extends({}, state, { | ||
transitionRoute: null, | ||
transitionError: null, | ||
previousRoute: action.payload.previousRoute, | ||
route: action.payload.route | ||
}); | ||
case CLEAR_ERRORS: | ||
return _extends({}, state, { | ||
transitionRoute: null, | ||
transitionError: null | ||
}); | ||
case TRANSITION_ERROR: | ||
return babelHelpers.extends({}, state, { | ||
transitionRoute: action.payload.route, | ||
transitionError: action.payload.transitionError | ||
}); | ||
default: | ||
return state; | ||
} | ||
} | ||
case CLEAR_ERRORS: | ||
return babelHelpers.extends({}, state, { | ||
transitionRoute: null, | ||
transitionError: null | ||
}); | ||
function nameToIDs(name) { | ||
return name.split('.').reduce(function (ids, name) { | ||
return ids.concat(ids.length ? ids[ids.length - 1] + '.' + name : name); | ||
}, []); | ||
} | ||
default: | ||
return state; | ||
} | ||
} | ||
function extractSegmentParams(name, state) { | ||
if (!state._meta || !state._meta[name]) return {}; | ||
function nameToIDs(name) { | ||
return name.split('.').reduce(function (ids, name) { | ||
return ids.concat(ids.length ? ids[ids.length - 1] + '.' + name : name); | ||
}, []); | ||
} | ||
return Object.keys(state._meta[name]).reduce(function (params, p) { | ||
params[p] = state.params[p]; | ||
return params; | ||
}, {}); | ||
} | ||
function extractSegmentParams(name, state) { | ||
if (!state._meta || !state._meta[name]) return {}; | ||
function transitionPath(toState, fromState) { | ||
var fromStateIds = fromState ? nameToIDs(fromState.name) : []; | ||
var toStateIds = nameToIDs(toState.name); | ||
var maxI = Math.min(fromStateIds.length, toStateIds.length); | ||
return Object.keys(state._meta[name]).reduce(function (params, p) { | ||
params[p] = state.params[p]; | ||
return params; | ||
}, {}); | ||
} | ||
function pointOfDifference() { | ||
var i = void 0; | ||
function transitionPath(toState, fromState) { | ||
var fromStateIds = fromState ? nameToIDs(fromState.name) : []; | ||
var toStateIds = nameToIDs(toState.name); | ||
var maxI = Math.min(fromStateIds.length, toStateIds.length); | ||
var _loop = function _loop() { | ||
var left = fromStateIds[i]; | ||
var right = toStateIds[i]; | ||
function pointOfDifference() { | ||
var i = void 0; | ||
if (left !== right) return { | ||
v: i | ||
}; | ||
var _loop = function _loop() { | ||
var left = fromStateIds[i]; | ||
var right = toStateIds[i]; | ||
var leftParams = extractSegmentParams(left, toState); | ||
var rightParams = extractSegmentParams(right, fromState); | ||
if (left !== right) return { | ||
v: i | ||
}; | ||
if (leftParams.length !== rightParams.length) return { | ||
v: i | ||
}; | ||
if (leftParams.length === 0) return 'continue'; | ||
var leftParams = extractSegmentParams(left, toState); | ||
var rightParams = extractSegmentParams(right, fromState); | ||
var different = Object.keys(leftParams).some(function (p) { | ||
return rightParams[p] !== leftParams[p]; | ||
}); | ||
if (different) { | ||
return { | ||
v: i | ||
}; | ||
} | ||
}; | ||
if (leftParams.length !== rightParams.length) return { | ||
v: i | ||
}; | ||
if (leftParams.length === 0) return 'continue'; | ||
for (i = 0; i < maxI; i += 1) { | ||
var _ret = _loop(); | ||
var different = Object.keys(leftParams).some(function (p) { | ||
return rightParams[p] !== leftParams[p]; | ||
}); | ||
if (different) { | ||
return { | ||
v: i | ||
}; | ||
} | ||
}; | ||
switch (_ret) { | ||
case 'continue': | ||
continue; | ||
for (i = 0; i < maxI; i += 1) { | ||
var _ret = _loop(); | ||
default: | ||
if ((typeof _ret === 'undefined' ? 'undefined' : typeof(_ret)) === "object") return _ret.v; | ||
} | ||
} | ||
switch (_ret) { | ||
case 'continue': | ||
continue; | ||
return i; | ||
} | ||
default: | ||
if ((typeof _ret === 'undefined' ? 'undefined' : babelHelpers.typeof(_ret)) === "object") return _ret.v; | ||
} | ||
} | ||
var i = void 0; | ||
if (!fromState) { | ||
i = 0; | ||
} else if (!fromState || toState.name === fromState.name && (!toState._meta || !fromState._meta)) { | ||
console.log('[router5.transition-path] Some states are missing metadata, reloading all segments'); | ||
i = 0; | ||
} else { | ||
i = pointOfDifference(); | ||
} | ||
return i; | ||
} | ||
var toDeactivate = fromStateIds.slice(i).reverse(); | ||
var toActivate = toStateIds.slice(i); | ||
var i = void 0; | ||
if (!fromState) { | ||
i = 0; | ||
} else if (!fromState || toState.name === fromState.name && (!toState._meta || !fromState._meta)) { | ||
console.log('[router5.transition-path] Some states are missing metadata, reloading all segments'); | ||
i = 0; | ||
} else { | ||
i = pointOfDifference(); | ||
} | ||
var intersection = fromState && i > 0 ? fromStateIds[i - 1] : ''; | ||
var toDeactivate = fromStateIds.slice(i).reverse(); | ||
var toActivate = toStateIds.slice(i); | ||
return { | ||
intersection: intersection, | ||
toDeactivate: toDeactivate, | ||
toActivate: toActivate | ||
}; | ||
} | ||
var intersection = fromState && i > 0 ? fromStateIds[i - 1] : ''; | ||
function routeNodeSelector(routeNode) { | ||
var reducerKey = arguments.length <= 1 || arguments[1] === undefined ? 'router' : arguments[1]; | ||
return { | ||
intersection: intersection, | ||
toDeactivate: toDeactivate, | ||
toActivate: toActivate | ||
}; | ||
} | ||
var routerStateSelector = function routerStateSelector(state) { | ||
return state[reducerKey] || state.get && state.get(reducerKey); | ||
}; | ||
var lastReturnedValue = void 0; | ||
function routeNodeSelector(routeNode) { | ||
var reducerKey = arguments.length <= 1 || arguments[1] === undefined ? 'router' : arguments[1]; | ||
return function (state) { | ||
var _routerStateSelector = routerStateSelector(state); | ||
var routerStateSelector = function routerStateSelector(state) { | ||
return state[reducerKey]; | ||
}; | ||
var lastReturnedValue = void 0; | ||
var route = _routerStateSelector.route; | ||
var previousRoute = _routerStateSelector.previousRoute; | ||
return function (state) { | ||
var _routerStateSelector = routerStateSelector(state); | ||
var intersection = route ? transitionPath(route, previousRoute).intersection : ''; | ||
var route = _routerStateSelector.route; | ||
var previousRoute = _routerStateSelector.previousRoute; | ||
if (!lastReturnedValue) { | ||
lastReturnedValue = { route: route, previousRoute: previousRoute }; | ||
} else if (!previousRoute || previousRoute !== route && intersection === routeNode) { | ||
lastReturnedValue = { route: route, previousRoute: previousRoute }; | ||
} | ||
var intersection = route ? transitionPath(route, previousRoute).intersection : ''; | ||
return lastReturnedValue; | ||
}; | ||
} | ||
if (!lastReturnedValue) { | ||
lastReturnedValue = { route: route, previousRoute: previousRoute }; | ||
} else if (!previousRoute || previousRoute !== route && intersection === routeNode) { | ||
lastReturnedValue = { route: route, previousRoute: previousRoute }; | ||
} | ||
exports.router5Middleware = router5ReduxMiddleware; | ||
exports.router5Reducer = router5Reducer; | ||
exports.actions = actions; | ||
exports.actionTypes = actionTypes; | ||
exports.routeNodeSelector = routeNodeSelector; | ||
exports.reduxPlugin = reduxPluginFactory; | ||
return lastReturnedValue; | ||
}; | ||
} | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.router5Middleware = router5ReduxMiddleware; | ||
exports.router5Reducer = router5Reducer; | ||
exports.actions = actions; | ||
exports.actionTypes = actionTypes; | ||
exports.routeNodeSelector = routeNodeSelector; | ||
exports.reduxPlugin = reduxPluginFactory; | ||
})); |
@@ -17,3 +17,3 @@ 'use strict'; | ||
var routerStateSelector = function routerStateSelector(state) { | ||
return state[reducerKey]; | ||
return state[reducerKey] || state.get && state.get(reducerKey); | ||
}; | ||
@@ -20,0 +20,0 @@ var lastReturnedValue = void 0; |
{ | ||
"name": "redux-router5", | ||
"version": "4.1.0", | ||
"version": "4.2.0", | ||
"description": "Router5 integration with redux", | ||
@@ -51,7 +51,9 @@ "main": "index.js", | ||
"rollup-plugin-npm": "^1.4.0", | ||
"yargs": "^4.7.1" | ||
"yargs": "^4.7.1", | ||
"immutable": "^3.0.0" | ||
}, | ||
"peerDependencies": { | ||
"router5": "^4.0.0", | ||
"redux": "^3.0.0" | ||
"redux": "^3.0.0", | ||
"immutable": "^3.0.0" | ||
}, | ||
@@ -58,0 +60,0 @@ "dependencies": { |
@@ -89,3 +89,9 @@ [](https://badge.fury.io/js/redux-router5) | ||
If you are using [immutable-js](https://github.com/facebook/immutable-js) and [redux-immutable](https://github.com/gajus/redux-immutable) simply use the reducer from 'redux-router5/immutable/reducer' | ||
```javascript | ||
import { router5Middleware } from 'redux-router5'; | ||
import router5Reducer from 'redux-router5/immutable/reducer'; | ||
``` | ||
## Router5 reduxPlugin | ||
@@ -92,0 +98,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
43131
20
792
194
0
4
16