react-selection-hoc
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -16,6 +16,2 @@ 'use strict'; | ||
var _debug = require('./debug.js'); | ||
var _debug2 = _interopRequireDefault(_debug); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -145,23 +141,6 @@ | ||
// if (!this.node) { // pretty sure this is unneeded. Keep just in case | ||
// this.node = findit(this.ref) | ||
// this.bounds = mouse.getBoundsForNode(this.node) | ||
// if (Debug.DEBUGGING.debug && Debug.DEBUGGING.bounds) { | ||
// Debug.log(`${eventname}: got bounds`, this.bounds) | ||
// } | ||
// } | ||
var coords = mouse.getCoordinates(e, e.touches && e.touches[0].identifier); | ||
if (!mouse.contains(this.node, coords.clientX, coords.clientY)) { | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.clicks) { | ||
_debug2.default.log(eventname + ': not contained'); | ||
} | ||
return; | ||
} | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.clicks) { | ||
_debug2.default.log(eventname + ': click/tap start'); | ||
} | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.bounds) { | ||
_debug2.default.log(eventname + ': bounds', this.bounds, e.pageY, e.pageX); | ||
} | ||
@@ -173,6 +152,2 @@ if (!mouse.objectsCollide(this.bounds, { | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.clicks) { | ||
_debug2.default.log(eventname + ': maybe select'); | ||
} | ||
this.mouseDownData = { | ||
@@ -179,0 +154,0 @@ x: coords.pageX, |
@@ -9,8 +9,2 @@ 'use strict'; | ||
var _debug = require('./debug.js'); | ||
var _debug2 = _interopRequireDefault(_debug); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -68,5 +62,4 @@ | ||
key: 'objectsCollide', | ||
value: function objectsCollide(nodeA, nodeB) { | ||
value: function objectsCollide(nodeA, nodeB) /* , key = '(unknown)' */{ | ||
var tolerance = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2]; | ||
var key = arguments.length <= 3 || arguments[3] === undefined ? '(unknown)' : arguments[3]; | ||
@@ -91,5 +84,2 @@ var _mouseMath$getBoundsF = mouseMath.getBoundsForNode(nodeA); | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.bounds) { | ||
_debug2.default.debugBounds(mouseMath.getBoundsForNode, nodeA, nodeB, key, tolerance); | ||
} | ||
@@ -96,0 +86,0 @@ return !( |
@@ -55,5 +55,5 @@ 'use strict'; | ||
}(_react2.default.Component), _class.displayName = 'ReferenceableContainer(' + componentDisplayName + ')', _class.propTypes = { | ||
children: _react.PropTypes.element | ||
children: _react.PropTypes.any | ||
}, _temp; | ||
} | ||
module.exports = exports['default']; |
@@ -23,2 +23,10 @@ 'use strict'; | ||
var _shallowEqual = require('./shallowEqual.js'); | ||
var _shallowEqual2 = _interopRequireDefault(_shallowEqual); | ||
var _shallowEqualScalar = require('./shallowEqualScalar.js'); | ||
var _shallowEqualScalar2 = _interopRequireDefault(_shallowEqualScalar); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -77,6 +85,15 @@ | ||
value: function register(props) { | ||
var types = ['default']; | ||
if (options.types) { | ||
if (options.types instanceof Function) { | ||
types = options.types(props); | ||
} else { | ||
types = options.types; | ||
} | ||
} | ||
this.key = options.key(this.props); | ||
this.context.selectionManager.registerSelectable(this, { | ||
key: options.key(this.props), | ||
key: this.key, | ||
selectable: options.selectable ? options.selectable(props) : true, | ||
types: options.types ? options.types : ['default'], | ||
types: types, | ||
value: options.value(props), | ||
@@ -91,5 +108,4 @@ callback: this.selectItem, | ||
if (!this.context || !this.context.selectionManager) return; | ||
var key = options.key(this.props); | ||
this.register(this.props); | ||
unregister = this.context.selectionManager.unregisterSelectable.bind(this.context.selectionManager, this, key); | ||
unregister = this.context.selectionManager.unregisterSelectable.bind(this.context.selectionManager, this, this.key); | ||
} | ||
@@ -107,3 +123,5 @@ }, { | ||
value: function selectItem(value) { | ||
if (value === this.state.selected) return; | ||
this.setState({ selected: value }); | ||
this.forceUpdate(); | ||
} | ||
@@ -117,2 +135,7 @@ }, { | ||
}, { | ||
key: 'shouldComponentUpdate', | ||
value: function shouldComponentUpdate(nextProps, nextState) { | ||
return !(0, _shallowEqualScalar2.default)(nextProps, this.props) || !(0, _shallowEqual2.default)(nextState, this.state); | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -119,0 +142,0 @@ value: function render() { |
@@ -42,2 +42,15 @@ 'use strict'; | ||
}, | ||
node: function node(idx) { | ||
return _this.nodes[idx]; | ||
}, | ||
nodeIndicesOfType: function nodeIndicesOfType(types) { | ||
var mytypes = [].concat(types); | ||
return _this.nodes.filter(function (node) { | ||
return mytypes.every(function (type) { | ||
return node.types.indexOf(type) !== -1; | ||
}); | ||
}).map(function (node) { | ||
return _this.nodes.indexOf(node); | ||
}); | ||
}, | ||
selectedIndices: function selectedIndices() { | ||
@@ -47,22 +60,16 @@ return [].concat(_toConsumableArray(_this.selectedIndices)); | ||
selectedNodeList: function selectedNodeList() { | ||
var _this2 = this; | ||
return _this.selectedIndices.map(function (idx) { | ||
return _this2.nodes[idx].component; | ||
return _this.nodes[idx].component; | ||
}); | ||
}, | ||
selectedValueList: function selectedValueList() { | ||
var _this3 = this; | ||
return _this.selectedIndices.map(function (idx) { | ||
return _this3.nodes[idx].value; | ||
return _this.nodes[idx].value; | ||
}); | ||
}, | ||
selectedNodes: function selectedNodes() { | ||
var _this4 = this; | ||
return _this.selectedIndices.reduce(function (val, idx) { | ||
val[_this4.nodes[idx].key] = { | ||
node: _this4.nodes[idx].component, | ||
bounds: _this4.bounds[idx] | ||
val[_this.nodes[idx].key] = { | ||
node: _this.nodes[idx].component, | ||
bounds: _this.bounds[idx] | ||
}; | ||
@@ -73,6 +80,4 @@ return val; | ||
selectedValues: function selectedValues() { | ||
var _this5 = this; | ||
return _this.selectedIndices.reduce(function (val, idx) { | ||
val[_this5.nodes[idx].key] = _this5.nodes[idx].value; | ||
val[_this.nodes[idx].key] = _this.nodes[idx].value; | ||
return val; | ||
@@ -87,7 +92,7 @@ }, {}); | ||
value: function setNodes(nodes) { | ||
var _this6 = this; | ||
var _this2 = this; | ||
this.nodes = nodes; | ||
this.nodes.forEach(function (node, idx) { | ||
return _this6.indices[node.key] = idx; | ||
return _this2.indices[node.key] = idx; | ||
}); | ||
@@ -101,2 +106,3 @@ } | ||
mostRecentSelection: [].concat(_toConsumableArray(selectedIndices)), | ||
additionalSelectionMap: {}, | ||
firstNode: false | ||
@@ -184,5 +190,2 @@ }; | ||
if (this.selectedIndices.indexOf(idx) !== -1) return; | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.selection) { | ||
_debug2.default.log('select new node', this.nodes[idx].key); | ||
} | ||
this.addItem(idx); | ||
@@ -193,5 +196,2 @@ } | ||
value: function deselectItem(idx) { | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.selection) { | ||
_debug2.default.log('deselect node', this.nodes[idx].key); | ||
} | ||
this.removeItem(idx); | ||
@@ -218,11 +218,5 @@ } | ||
// node is in the selection rectangle | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.selection) { | ||
_debug2.default.log('node is in selection rectangle', node.key); | ||
} | ||
this.selectItem(idx); | ||
} else { | ||
// node is not in the selection rectangle | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.selection) { | ||
_debug2.default.log('node is not in selection rectangle', node.key); | ||
} | ||
this.deselectItem(idx); | ||
@@ -241,7 +235,7 @@ } | ||
value: function xor(newSelected, prevSelected) { | ||
var _this7 = this; | ||
var _this3 = this; | ||
var ret = [].concat(_toConsumableArray(prevSelected)); | ||
newSelected.forEach(function (idx) { | ||
return prevSelected.indexOf(idx) === -1 ? _this7.addItem(idx, ret) : ret.splice(ret.indexOf(idx), 1); | ||
return prevSelected.indexOf(idx) === -1 ? _this3.addItem(idx, ret) : ret.splice(ret.indexOf(idx), 1); | ||
}); | ||
@@ -253,7 +247,7 @@ return ret; | ||
value: function or(newSelected, prevSelected) { | ||
var _this8 = this; | ||
var _this4 = this; | ||
var ret = [].concat(_toConsumableArray(prevSelected)); | ||
newSelected.forEach(function (idx) { | ||
return prevSelected.indexOf(idx) === -1 ? _this8.addItem(idx, ret) : null; | ||
return prevSelected.indexOf(idx) === -1 ? _this4.addItem(idx, ret) : null; | ||
}); | ||
@@ -265,3 +259,3 @@ return ret; | ||
value: function selectItemsInRectangle(selectionRectangle, props) { | ||
var _this9 = this; | ||
var _this5 = this; | ||
@@ -287,4 +281,4 @@ var findit = arguments.length <= 2 || arguments[2] === undefined ? _reactDom.findDOMNode : arguments[2]; | ||
(function () { | ||
var min = Math.min.apply(Math, _toConsumableArray(_this9.selectedIndices)); | ||
var max = Math.max.apply(Math, _toConsumableArray(_this9.selectedIndices)); | ||
var min = Math.min.apply(Math, _toConsumableArray(_this5.selectedIndices)); | ||
var max = Math.max.apply(Math, _toConsumableArray(_this5.selectedIndices)); | ||
var filled = Array.apply(min, Array(max - min)).map(function (x, y) { | ||
@@ -298,3 +292,3 @@ return min + y + 1; | ||
filled.forEach(function (idx) { | ||
return _this9.selectItem(idx); | ||
return _this5.selectItem(idx); | ||
}); | ||
@@ -311,5 +305,9 @@ })(); | ||
var test = this.transaction.additionalSelectionMap[this.keyize(this.selectedIndices)]; | ||
if (test) { | ||
this.selectedIndices = test; | ||
} | ||
if (this.selectedIndices.length === this.transaction.mostRecentSelection.length) { | ||
if (this.selectedIndices.every(function (idx, i) { | ||
return _this9.transaction.mostRecentSelection[i] === idx; | ||
return _this5.transaction.mostRecentSelection[i] === idx; | ||
})) return false; | ||
@@ -326,9 +324,9 @@ } | ||
value: function notifyChangedNodes() { | ||
var _this10 = this; | ||
var _this6 = this; | ||
this.removed.map(function (idx) { | ||
return _this10.nodes[idx].callback ? _this10.nodes[idx].callback(false) : null; | ||
return _this6.nodes[idx].callback ? _this6.nodes[idx].callback(false) : null; | ||
}); | ||
this.added.map(function (idx) { | ||
return _this10.nodes[idx].callback ? _this10.nodes[idx].callback(true) : null; | ||
return _this6.nodes[idx].callback ? _this6.nodes[idx].callback(true) : null; | ||
}); | ||
@@ -339,8 +337,11 @@ } | ||
value: function clear() { | ||
var _this11 = this; | ||
var _this7 = this; | ||
this.added = []; | ||
this.removed = []; | ||
if (this.selectedIndices.length === 0) return false; | ||
this.selectedIndices.forEach(function (idx) { | ||
return _this11.nodes[idx].callback && _this11.nodes[idx].callback(false); | ||
return _this7.nodes[idx].callback && _this7.nodes[idx].callback(false); | ||
}); | ||
this.selectedIndices = []; | ||
return true; | ||
@@ -351,3 +352,3 @@ } | ||
value: function revert() { | ||
var _this12 = this; | ||
var _this8 = this; | ||
@@ -358,14 +359,21 @@ var add = this.removed; | ||
add.forEach(function (idx) { | ||
return _this12.addItem(idx, _this12.selectedIndices); | ||
return _this8.addItem(idx, _this8.selectedIndices); | ||
}); | ||
remove.forEach(function (idx) { | ||
return _this12.removeItem(idx, _this12.selectedIndices); | ||
return _this8.removeItem(idx, _this8.selectedIndices); | ||
}); | ||
} | ||
}, { | ||
key: 'keyize', | ||
value: function keyize(indices) { | ||
return indices.toString(); | ||
} | ||
}, { | ||
key: 'setSelection', | ||
value: function setSelection(indices) { | ||
this.selectedIndices = indices; | ||
this.transaction.additionalSelectionMap[this.keyize(this.selectedIndices)] = indices; | ||
this.selectedIndices = [].concat(_toConsumableArray(indices)); | ||
this.removed = this.changed(this.selectedIndices, this.transaction.previousMostRecentSelection); | ||
this.added = this.changed(this.transaction.previousMostRecentSelection, this.selectedIndices); | ||
this.mostRecentSelection = [].concat(_toConsumableArray(indices)); | ||
} | ||
@@ -372,0 +380,0 @@ }]); |
@@ -102,3 +102,3 @@ 'use strict'; | ||
this.selectedList.revert(); | ||
} else if (result !== true) { | ||
} else if (result && result !== true) { | ||
this.selectedList.setSelection(result); | ||
@@ -129,3 +129,3 @@ } | ||
} | ||
this.props.selectionCallbacks.onFinishSelect(this.state.selectedIndices, this.selectedList, this.bounds); | ||
this.props.selectionCallbacks.onFinishSelect(this.state.selectedIndices, this.selectedList.accessor, this.bounds); | ||
} | ||
@@ -142,2 +142,12 @@ }, { | ||
}, { | ||
key: 'componentDidMount', | ||
value: function componentDidMount() { | ||
this.selectedList.setNodes(this.selectionManager.sortedNodes); | ||
} | ||
}, { | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate() { | ||
this.selectedList.setNodes(this.selectionManager.sortedNodes); | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
@@ -144,0 +154,0 @@ value: function componentWillUnmount() { |
@@ -15,6 +15,2 @@ 'use strict'; | ||
var _debug = require('./debug.js'); | ||
var _debug2 = _interopRequireDefault(_debug); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -38,16 +34,2 @@ | ||
_createClass(SelectionManager, [{ | ||
key: 'changeType', | ||
value: function changeType(key, types) { | ||
this.selectables[key].types = types; | ||
this.sortedNodes[this.indexMap[key]].types = types; | ||
this.selectedList.setNodes(this.sortedNodes); | ||
} | ||
}, { | ||
key: 'changeSelectable', | ||
value: function changeSelectable(key, selectable) { | ||
this.selectables[key].selectable = selectable; | ||
this.sortedNodes[this.indexMap[key]].selectable = selectable; | ||
this.selectedList.setNodes(this.sortedNodes); | ||
} | ||
}, { | ||
key: 'registerSelectable', | ||
@@ -77,7 +59,3 @@ value: function registerSelectable(component, _ref) { | ||
} | ||
if (_debug2.default.DEBUGGING.debug && _debug2.default.DEBUGGING.registration) { | ||
_debug2.default.log('registered: ' + key, value); | ||
} | ||
this.selectables[key] = info; | ||
this.selectedList.setNodes(this.sortedNodes); | ||
} | ||
@@ -111,8 +89,4 @@ }, { | ||
value: function cancelSelection(_ref3) { | ||
var _ref3$indices = _ref3.indices; | ||
var indices = _ref3$indices === undefined ? undefined : _ref3$indices; | ||
var _ref3$nodes = _ref3.nodes; | ||
var nodes = _ref3$nodes === undefined ? undefined : _ref3$nodes; | ||
var _ref3$values = _ref3.values; | ||
var values = _ref3$values === undefined ? undefined : _ref3$values; | ||
var indices = _ref3.indices; | ||
var nodes = _ref3.nodes; | ||
@@ -125,5 +99,2 @@ if (indices) { | ||
} | ||
if (values) { | ||
return this.selectedList.removeValues(values); | ||
} | ||
} | ||
@@ -130,0 +101,0 @@ }, { |
@@ -0,1 +1,10 @@ | ||
0.4.1 / 2016-06-26 | ||
------------------ | ||
- fix the accessor passed to an onSelectionChange callback | ||
- allow the "types" option passed to Selectable to be a function for dynamic typing | ||
- fix strictness in ReferenceableContainer that broke real-world examples | ||
- new accessors "node" and "nodeIndicesOfType" | ||
- fix broken onSelectionChange callback | ||
- minor performance improvements | ||
0.4.0 / 2016-06-22 | ||
@@ -2,0 +11,0 @@ ================== |
@@ -5,3 +5,3 @@ /* eslint no-var: 0, babel/object-shorthand: 0, vars-on-top: 0 */ | ||
var isCI = process.env.CONTINUOUS_INTEGRATION === 'true' | ||
var reporters = ['mocha', 'saucelabs'] | ||
var reporters = ['mocha', 'saucelabs', 'coverage'] | ||
var singleRun = true | ||
@@ -12,5 +12,30 @@ | ||
username: process.env.SAUCEUSER, | ||
accessKey: process.env.ACCESSSAUCE | ||
accessKey: process.env.ACCESSSAUCE, | ||
connectOptions: { | ||
logfile: 'sauce_connect.log' | ||
} | ||
} | ||
var coverageReporter = isCI ? { | ||
reporters: [ | ||
{ | ||
type: 'lcov', | ||
dir: 'coverage' | ||
}, | ||
{ | ||
type: 'text' | ||
} | ||
] | ||
} : { | ||
reporters: [ | ||
{ | ||
type: 'lcov', | ||
dir: 'coverage' | ||
}, | ||
{ | ||
type: 'text' | ||
} | ||
] | ||
} | ||
const frameworks = ['mocha', 'sinon-chai'] | ||
if (isCI) { | ||
@@ -28,14 +53,10 @@ sauceParams.build = process.env.TRAVIS_BUILD_NUMBER | ||
frameworks: [ | ||
'mocha-debug', | ||
'mocha', | ||
'sinon-chai' | ||
], | ||
frameworks, | ||
files: [ | ||
'test/index.js' | ||
'test/*.test.js' | ||
], | ||
preprocessors: { | ||
'test/index.js': ['webpack', 'sourcemap'] | ||
'test/*.test.js': ['webpack'], | ||
}, | ||
@@ -65,5 +86,7 @@ | ||
captureTimeout: 1200000, | ||
browserNoActivityTimeout: 45000, | ||
coverageReporter, | ||
captureTimeout: 2400000, | ||
browserNoActivityTimeout: 240000, | ||
singleRun, | ||
@@ -70,0 +93,0 @@ |
@@ -7,5 +7,5 @@ /* eslint no-var: 0, babel/object-shorthand: 0, vars-on-top: 0 */ | ||
return karma(config, { | ||
browsers: ['Chrome'], | ||
browsers: ['Chrome', 'Safari'], | ||
singleRun: false | ||
}) | ||
} |
@@ -7,2 +7,3 @@ The MIT License (MIT) | ||
Portions based on react-big-calendar Jason Quense (c) 2015 | ||
Portions based on react-dnd Dan Abramov (c) 2014 | ||
@@ -9,0 +10,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "react-selection-hoc", | ||
"author": "Gregory Beaver", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "Make any React-based collection of similar components selectable", | ||
@@ -15,3 +15,4 @@ "main": "build/index.js", | ||
"clean:examples": "rimraf examples/static", | ||
"test": "karma start karma.noie.conf.js && karma start karma.ie.conf.js", | ||
"test": "./node_modules/karma/bin/karma start karma.noie.conf.js && ./node_modules/karma/bin/karma start karma.ie.conf.js", | ||
"old-test": "NODE_ENV=test ./node_modules/karma/bin/karma start karma.noie.conf.js && NODE_ENV=test ./node_modules/karma/bin/karma start karma.ie.conf.js && ./node_modules/.bin/lcov-result-merger 'coverage/*/lcov.info' 'coverage/lcov.info' && ./node_modules/codeclimate-test-reporter/bin/codeclimate.js", | ||
"local-test": "./local-test.env", | ||
@@ -33,4 +34,8 @@ "test-cov": "babel-node isparta cover --report html --report text node_modules/.bin/_mocha", | ||
"babel-eslint": "^4.1.8", | ||
"babel-plugin-__coverage__": "^11.0.0", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-transform-es2015-spread": "^6.8.0", | ||
"babel-plugin-transform-object-assign": "^6.8.0", | ||
"babel-plugin-transform-runtime": "^6.9.0", | ||
"babel-polyfill": "^6.9.1", | ||
"babel-preset-es2015": "^6.1.18", | ||
@@ -40,15 +45,17 @@ "babel-preset-stage-0": "^6.1.18", | ||
"babel-register": "^6.9.0", | ||
"babel-runtime": "^6.9.2", | ||
"chai": "^3.5.0", | ||
"codeclimate-test-reporter": "^0.3.3", | ||
"eslint": "^1.9.0", | ||
"eslint-config-airbnb": "^1.0.0", | ||
"eslint-plugin-react": "^3.16.1", | ||
"graceful-fs": "^4.1.4", | ||
"isparta": "^4.0.0", | ||
"isparta-loader": "^2.0.0", | ||
"jsdom": "^9.2.1", | ||
"karma": "^0.13.22", | ||
"karma": "^1.0.0", | ||
"karma-babel-preprocessor": "^6.0.1", | ||
"karma-browserstack-launcher": "^1.0.1", | ||
"karma-chrome-launcher": "^1.0.1", | ||
"karma-firefox-launcher": "^1.0.0", | ||
"karma-coverage": "^1.0.0", | ||
"karma-mocha": "^1.0.1", | ||
"karma-mocha-debug": "^0.1.2", | ||
"karma-mocha-reporter": "^2.0.4", | ||
@@ -59,6 +66,7 @@ "karma-safari-launcher": "^1.0.0", | ||
"karma-sinon-chai": "^1.2.0", | ||
"karma-sourcemap-loader": "^0.3.7", | ||
"karma-webpack": "^1.7.0", | ||
"lcov-result-merger": "^1.2.0", | ||
"lolex": "^1.5.0", | ||
"mocha": "^2.3.4", | ||
"raw-loader": "^0.5.1", | ||
"rimraf": "^2.5.2", | ||
@@ -69,2 +77,3 @@ "selenium-webdriver": "^2.53.2", | ||
"sinon-chai": "^2.8.0", | ||
"style-loader": "^0.13.1", | ||
"teaspoon": "^6.4.0" | ||
@@ -71,0 +80,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1047994
31
1535
46