<commit_before>import React, {Component} from "react";
import TranslateWithLinks from "../Utility/TranslateWithLinks";
import {
    Input,
    Form,
    Select,
    Button,
    Col,
    Row,
    Radio
} from "bitshares-ui-style-guide";
import AssetNameWrapper from "../Utility/AssetName";
import {SCALED_ORDER_ACTION_TYPES} from "../../services/Exchange";
import {Asset} from "../../lib/common/MarketClasses";
import ChainStore from "bitsharesjs/es/chain/src/ChainStore";
import counterpart from "counterpart";
import {Validation} from "../../services/Validation/Validation";
import assetUtils from "../../lib/common/asset_utils";
import {checkFeeStatusAsync} from "../../lib/common/trxHelper";
import PriceText from "../Utility/PriceText";
import {
    preciseAdd,
    preciseDivide,
    preciseMultiply,
    preciseMinus
} from "../../services/Math";

class ScaledOrderForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            orderCount: 1,
            feeAssets: []
        };

        this.handleClickBalance = this.handleClickBalance.bind(this);
        this.handleCurrentPriceClick = this.handleCurrentPriceClick.bind(this);
    }

    componentDidMount() {
        this._checkFeeAssets();
    }

    componentDidUpdate() {
        const orderCount = Number(this._getFormValues().orderCount || 1);
        const stateOrderCount = Number(this.state.orderCount);

        if (
            !isNaN(stateOrderCount) &&
            !isNaN(orderCount) &&
            Number(this.state.orderCount) !== orderCount
        ) {
            this.setState(
                {
                    orderCount: orderCount
                },
                () => {
                    this._checkFeeAssets();
                }
            );
        }
    }

    _getBaseAssetFlags() {
        return assetUtils.getFlagBooleans(
            this.props.baseAsset.getIn(["options", "flags"]),
            this.props.baseAsset.has("bitasset_data_id")
        );
    }

    _getQuoteAssetFlags() {
        return assetUtils.getFlagBooleans(
            this.props.quoteAsset.getIn(["options", "flags"]),
            this.props.quoteAsset.has("bitasset_data_id")
        );
    }

    _isMarketFeeVisible() {
        const baseAssetFlagBooleans = this._getBaseAssetFlags();

        const quoteAssetFlagBooleans = this._getQuoteAssetFlags();

        if (
            this._getFormValues().action === SCALED_ORDER_ACTION_TYPES.SELL &&
            baseAssetFlagBooleans.charge_market_fee
        ) {
            return true;
        }

        if (
            this._getFormValues().action === SCALED_ORDER_ACTION_TYPES.BUY &&
            quoteAssetFlagBooleans.charge_market_fee
        ) {
            return true;
        }

        return false;
    }

    _getFormValues() {
        return this.props.form.getFieldsValue();
    }

    _filterFeeStatuses(feeStatuses) {
        return feeStatuses
            .filter(feeStatus => {
                return (
                    feeStatus &&
                    feeStatus.hasPoolBalance &&
                    feeStatus.hasBalance
                );
            })
            .map(feeStatus => {
                return {
                    fee: feeStatus,
                    amount:
                        feeStatus.fee.getAmount() /
                        Math.pow(10, feeStatus.fee.precision),
                    asset: ChainStore.getAsset(feeStatus.fee.asset_id)
                };
            });
    }

    _checkFeeAssets() {
        // get account balances, check is each balance available to pay fee
        // for limit_order, filter only available assets and put it to local state

        this._getAccountAssetsFeeStatus().then(feeStatuses => {
            let assets = this._filterFeeStatuses(feeStatuses);

            this.setState({
                feeAssets: assets
            });
        });
    }

    _getAccountAssetsFeeStatus() {
        const {currentAccount} = this.props;

        const {orderCount} = this._getFormValues();

        if (
            !currentAccount ||
            !currentAccount.get ||
            !currentAccount.get("balances")
        ) {
            return false;
        }

        return new Promise(resolve => {
            let promises = [];

            currentAccount.get("balances").forEach(balance => {
                let balanceObj = ChainStore.getObject(balance);

                let promise = checkFeeStatusAsync({
                    accountID: currentAccount.get("id"),
                    feeID: balanceObj.get("asset_type"),
                    type: "limit_order_create",
                    operationsCount: orderCount
                });

                promises.push(promise);
            });

            Promise.all(promises).then(feesStatuses => {
                resolve(feesStatuses);
            });
        });
    }

    _getFee() {
        const formValues = this._getFormValues();

        let amount = 0;

        if (formValues && formValues.feeCurrency) {
            this.state.feeAssets.forEach(feeAsset => {
                if (
                    feeAsset &&
                    feeAsset.asset &&
                    feeAsset.asset.get("symbol") === formValues.feeCurrency
                ) {
                    amount = feeAsset.amount;
                }
            });
        }

        return amount;
    }

    _getMarketFee() {
        const formValues = this._getFormValues();

        const base = this.props.baseAsset;
        const quote = this.props.quoteAsset;

        const quantity = Number(this._getTotal());
        const action = formValues.action;

        if (isNaN(quantity)) return null;

        let asset = null;

        if (action === SCALED_ORDER_ACTION_TYPES.SELL) asset = base;

        if (action === SCALED_ORDER_ACTION_TYPES.BUY) asset = quote;

        if (!asset || !asset.get || !asset.getIn) return null;

        const maxMarketFee = new Asset({
            amount: asset.getIn(["options", "max_market_fee"]),
            asset_id: asset.get("asset_id"),
            precision: asset.get("precision")
        });

        const marketFeePercent = this._getMarketFeePercentage();

        return !quantity
            ? 0
            : Math.min(
                  maxMarketFee.getAmount({real: true}),
                  (quantity / 100) * marketFeePercent
              ).toFixed(maxMarketFee.precision);
    }

    _getMarketFeePercentage() {
        const {action} = this._getFormValues();

        const base = this.props.baseAsset;
        const quote = this.props.quoteAsset;

        let asset = null;

        if (action === SCALED_ORDER_ACTION_TYPES.SELL) asset = base;

        if (action === SCALED_ORDER_ACTION_TYPES.BUY) asset = quote;

        return Number(asset.getIn(["options", "market_fee_percent"]) / 100);
    }

    _getTotal() {
        const formValues = this._getFormValues();

        const amount = Number(formValues.amount);
        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(amount) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return 0;

        const step = preciseDivide(
            preciseMinus(priceUpper, priceLower),
            preciseMinus(orderCount, 1)
        );

        const amountPerOrder = preciseDivide(amount, orderCount);

        let total = 0;

        for (let i = 0; i < orderCount; i += 1) {
            // total += amountPerOrder * (priceLower + step * i);
            total = preciseAdd(
                total,
                preciseMultiply(
                    amountPerOrder,
                    preciseAdd(priceLower, preciseMultiply(step, i))
                )
            );
        }

        return total;
    }

    _getQuantityFromTotal(total) {
        const formValues = this._getFormValues();

        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(total) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return 0;

        const step = preciseDivide(
            preciseMinus(priceUpper, priceLower),
            preciseMinus(orderCount, 1)
        );

        let sum = 0;

        for (let i = 0; i < orderCount; i += 1) {
            // sum + ((priceLower + step * i) / orderCount)

            sum = preciseAdd(
                sum,
                Number(
                    preciseDivide(
                        preciseAdd(priceLower, preciseMultiply(step, i)),
                        orderCount
                    )
                )
            );
        }

        return preciseDivide(total, sum);
    }

    _getPreviewDataSource() {
        const formValues = this._getFormValues();

        const dataSource = [];

        const action = formValues.action;
        const amount = Number(formValues.amount);
        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(amount) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return [];

        const step = ((priceUpper - priceLower) / (orderCount - 1)).toFixed(6);

        const amountPerOrder = amount / orderCount;

        for (let i = 0; i < orderCount; i += 1) {
            dataSource.push({
                quote: amountPerOrder.toFixed(6),
                base: (amountPerOrder * (priceLower + step * i)).toFixed(6),
                price: (priceLower + step * i).toFixed(6)
            });
        }

        return action === SCALED_ORDER_ACTION_TYPES.BUY
            ? dataSource.reverse()
            : dataSource;
    }

    handleClickBalance() {
        if (this.props.type === "bid") {
            this.props.form.setFieldsValue({
                amount: this._getQuantityFromTotal(this.props.baseAssetBalance)
            });
        } else {
            this.props.form.setFieldsValue({
                amount: this.props.quoteAssetBalance
            });
        }
    }

    handleCurrentPriceClick() {
        this.props.form.setFieldsValue({
            priceLower: this.props.currentPrice
        });
    }

    render() {
        const {type, quoteAsset, baseAsset, currentAccount} = this.props;

        const isBid = type === "bid";

        const quote = quoteAsset;
        const base = baseAsset;

        const {getFieldDecorator} = this.props.form;

        const marketFeeSymbol = (
            <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />
        );

        const quantitySymbol = (
            <AssetNameWrapper name={this.props.quoteAsset.get("symbol")} />
        );

        const totalSymbol = (
            <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />
        );

        const priceSymbol = (
            <div
                style={{
                    maxWidth: "110px",
                    display: "block",
                    overflow: "hidden",
                    textOverflow: "ellipsis"
                }}
            >
                <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />/
                <AssetNameWrapper name={this.props.quoteAsset.get("symbol")} />
            </div>
        );

        const formItemProps = {
            labelCol: {span: 6},
            wrapperCol: {span: 18}
        };

        const actionRadio = getFieldDecorator("action", {
            initialValue: isBid
                ? SCALED_ORDER_ACTION_TYPES.BUY
                : SCALED_ORDER_ACTION_TYPES.SELL
        })(
            <Radio.Group>
                <Radio value={SCALED_ORDER_ACTION_TYPES.BUY}>
                    {counterpart.translate("scaled_orders.action.buy")}
                </Radio>
                <Radio value={SCALED_ORDER_ACTION_TYPES.SELL}>
                    {counterpart.translate("scaled_orders.action.sell")}
                </Radio>
            </Radio.Group>
        );

        const priceLowerInput = getFieldDecorator("priceLower", {
            validateFirst: true,
            validateTrigger: "onBlur",
            rules: [
                Validation.Rules.required(),
                Validation.Rules.number(),
                Validation.Rules.min({min: 0, name: "Price", higherThan: true})
            ]
        })(
            <Input
                placeholder="0.0"
                style={{width: "100%"}}
                autoComplete="off"
                addonAfter={priceSymbol}
            />
        );

        const priceUpperInput = getFieldDecorator("priceUpper", {
            validateFirst: true,
            validateTrigger: "onBlur",
            rules: [
                Validation.Rules.required(),
                Validation.Rules.number(),
                Validation.Rules.min({min: 0, name: "Price", higherThan: true})
            ]
        })(
            <Input
                placeholder="0.0"
                style={{width: "100%"}}
                autoComplete="off"
                addonAfter={priceSymbol}
            />
        );

        const feeCurrencySelect = getFieldDecorator("feeCurrency", {
            initialValue:
                ChainStore.getAsset("1.3.0") &&
                ChainStore.getAsset("1.3.0").get &&
                ChainStore.getAsset("1.3.0").get("symbol")
        })(
            <Select
                showSearch
                dropdownMatchSelectWidth={false}
                style={{minWidth: "80px", maxWidth: "120px"}}
            >
                {this.state.feeAssets &&
                    this.state.feeAssets.map &&
                    this.state.feeAssets.map(feeAsset => {
                        return (<commit_msg>#2497 Display error message if priceLower equal priceUpper<commit_after>import React, {Component} from "react";
import TranslateWithLinks from "../Utility/TranslateWithLinks";
import {
    Input,
    Form,
    Select,
    Button,
    Col,
    Row,
    Radio
} from "bitshares-ui-style-guide";
import AssetNameWrapper from "../Utility/AssetName";
import {SCALED_ORDER_ACTION_TYPES} from "../../services/Exchange";
import {Asset} from "../../lib/common/MarketClasses";
import ChainStore from "bitsharesjs/es/chain/src/ChainStore";
import counterpart from "counterpart";
import {Validation} from "../../services/Validation/Validation";
import assetUtils from "../../lib/common/asset_utils";
import {checkFeeStatusAsync} from "../../lib/common/trxHelper";
import PriceText from "../Utility/PriceText";
import {
    preciseAdd,
    preciseDivide,
    preciseMultiply,
    preciseMinus
} from "../../services/Math";

class ScaledOrderForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            orderCount: 1,
            feeAssets: []
        };

        this.handleClickBalance = this.handleClickBalance.bind(this);
        this.handleCurrentPriceClick = this.handleCurrentPriceClick.bind(this);
    }

    componentDidMount() {
        this._checkFeeAssets();
    }

    componentDidUpdate() {
        const orderCount = Number(this._getFormValues().orderCount || 1);
        const stateOrderCount = Number(this.state.orderCount);

        if (
            !isNaN(stateOrderCount) &&
            !isNaN(orderCount) &&
            Number(this.state.orderCount) !== orderCount
        ) {
            this.setState(
                {
                    orderCount: orderCount
                },
                () => {
                    this._checkFeeAssets();
                }
            );
        }
    }

    _getBaseAssetFlags() {
        return assetUtils.getFlagBooleans(
            this.props.baseAsset.getIn(["options", "flags"]),
            this.props.baseAsset.has("bitasset_data_id")
        );
    }

    _getQuoteAssetFlags() {
        return assetUtils.getFlagBooleans(
            this.props.quoteAsset.getIn(["options", "flags"]),
            this.props.quoteAsset.has("bitasset_data_id")
        );
    }

    _isMarketFeeVisible() {
        const baseAssetFlagBooleans = this._getBaseAssetFlags();

        const quoteAssetFlagBooleans = this._getQuoteAssetFlags();

        if (
            this._getFormValues().action === SCALED_ORDER_ACTION_TYPES.SELL &&
            baseAssetFlagBooleans.charge_market_fee
        ) {
            return true;
        }

        if (
            this._getFormValues().action === SCALED_ORDER_ACTION_TYPES.BUY &&
            quoteAssetFlagBooleans.charge_market_fee
        ) {
            return true;
        }

        return false;
    }

    _getFormValues() {
        return this.props.form.getFieldsValue();
    }

    _filterFeeStatuses(feeStatuses) {
        return feeStatuses
            .filter(feeStatus => {
                return (
                    feeStatus &&
                    feeStatus.hasPoolBalance &&
                    feeStatus.hasBalance
                );
            })
            .map(feeStatus => {
                return {
                    fee: feeStatus,
                    amount:
                        feeStatus.fee.getAmount() /
                        Math.pow(10, feeStatus.fee.precision),
                    asset: ChainStore.getAsset(feeStatus.fee.asset_id)
                };
            });
    }

    _checkFeeAssets() {
        // get account balances, check is each balance available to pay fee
        // for limit_order, filter only available assets and put it to local state

        this._getAccountAssetsFeeStatus().then(feeStatuses => {
            let assets = this._filterFeeStatuses(feeStatuses);

            this.setState({
                feeAssets: assets
            });
        });
    }

    _getAccountAssetsFeeStatus() {
        const {currentAccount} = this.props;

        const {orderCount} = this._getFormValues();

        if (
            !currentAccount ||
            !currentAccount.get ||
            !currentAccount.get("balances")
        ) {
            return false;
        }

        return new Promise(resolve => {
            let promises = [];

            currentAccount.get("balances").forEach(balance => {
                let balanceObj = ChainStore.getObject(balance);

                let promise = checkFeeStatusAsync({
                    accountID: currentAccount.get("id"),
                    feeID: balanceObj.get("asset_type"),
                    type: "limit_order_create",
                    operationsCount: orderCount
                });

                promises.push(promise);
            });

            Promise.all(promises).then(feesStatuses => {
                resolve(feesStatuses);
            });
        });
    }

    _getFee() {
        const formValues = this._getFormValues();

        let amount = 0;

        if (formValues && formValues.feeCurrency) {
            this.state.feeAssets.forEach(feeAsset => {
                if (
                    feeAsset &&
                    feeAsset.asset &&
                    feeAsset.asset.get("symbol") === formValues.feeCurrency
                ) {
                    amount = feeAsset.amount;
                }
            });
        }

        return amount;
    }

    _getMarketFee() {
        const formValues = this._getFormValues();

        const base = this.props.baseAsset;
        const quote = this.props.quoteAsset;

        const quantity = Number(this._getTotal());
        const action = formValues.action;

        if (isNaN(quantity)) return null;

        let asset = null;

        if (action === SCALED_ORDER_ACTION_TYPES.SELL) asset = base;

        if (action === SCALED_ORDER_ACTION_TYPES.BUY) asset = quote;

        if (!asset || !asset.get || !asset.getIn) return null;

        const maxMarketFee = new Asset({
            amount: asset.getIn(["options", "max_market_fee"]),
            asset_id: asset.get("asset_id"),
            precision: asset.get("precision")
        });

        const marketFeePercent = this._getMarketFeePercentage();

        return !quantity
            ? 0
            : Math.min(
                  maxMarketFee.getAmount({real: true}),
                  (quantity / 100) * marketFeePercent
              ).toFixed(maxMarketFee.precision);
    }

    _getMarketFeePercentage() {
        const {action} = this._getFormValues();

        const base = this.props.baseAsset;
        const quote = this.props.quoteAsset;

        let asset = null;

        if (action === SCALED_ORDER_ACTION_TYPES.SELL) asset = base;

        if (action === SCALED_ORDER_ACTION_TYPES.BUY) asset = quote;

        return Number(asset.getIn(["options", "market_fee_percent"]) / 100);
    }

    _getTotal() {
        const formValues = this._getFormValues();

        const amount = Number(formValues.amount);
        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(amount) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return 0;

        const step = preciseDivide(
            preciseMinus(priceUpper, priceLower),
            preciseMinus(orderCount, 1)
        );

        const amountPerOrder = preciseDivide(amount, orderCount);

        let total = 0;

        for (let i = 0; i < orderCount; i += 1) {
            // total += amountPerOrder * (priceLower + step * i);
            total = preciseAdd(
                total,
                preciseMultiply(
                    amountPerOrder,
                    preciseAdd(priceLower, preciseMultiply(step, i))
                )
            );
        }

        return total;
    }

    _getQuantityFromTotal(total) {
        const formValues = this._getFormValues();

        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(total) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return 0;

        const step = preciseDivide(
            preciseMinus(priceUpper, priceLower),
            preciseMinus(orderCount, 1)
        );

        let sum = 0;

        for (let i = 0; i < orderCount; i += 1) {
            // sum + ((priceLower + step * i) / orderCount)

            sum = preciseAdd(
                sum,
                Number(
                    preciseDivide(
                        preciseAdd(priceLower, preciseMultiply(step, i)),
                        orderCount
                    )
                )
            );
        }

        return preciseDivide(total, sum);
    }

    _getPreviewDataSource() {
        const formValues = this._getFormValues();

        const dataSource = [];

        const action = formValues.action;
        const amount = Number(formValues.amount);
        const priceLower = Number(formValues.priceLower);
        const priceUpper = Number(formValues.priceUpper);
        const orderCount = Number(formValues.orderCount);

        const isCorrect = value => !isNaN(value);

        if (
            !isCorrect(priceLower) ||
            !isCorrect(priceUpper) ||
            !isCorrect(amount) ||
            !isCorrect(orderCount) ||
            orderCount <= 0 ||
            priceLower >= priceUpper
        )
            return [];

        const step = ((priceUpper - priceLower) / (orderCount - 1)).toFixed(6);

        const amountPerOrder = amount / orderCount;

        for (let i = 0; i < orderCount; i += 1) {
            dataSource.push({
                quote: amountPerOrder.toFixed(6),
                base: (amountPerOrder * (priceLower + step * i)).toFixed(6),
                price: (priceLower + step * i).toFixed(6)
            });
        }

        return action === SCALED_ORDER_ACTION_TYPES.BUY
            ? dataSource.reverse()
            : dataSource;
    }

    handleClickBalance() {
        if (this.props.type === "bid") {
            this.props.form.setFieldsValue({
                amount: this._getQuantityFromTotal(this.props.baseAssetBalance)
            });
        } else {
            this.props.form.setFieldsValue({
                amount: this.props.quoteAssetBalance
            });
        }
    }

    handleCurrentPriceClick() {
        this.props.form.setFieldsValue({
            priceLower: this.props.currentPrice
        });
    }

    render() {
        const {type, quoteAsset, baseAsset, currentAccount} = this.props;

        const isBid = type === "bid";

        const quote = quoteAsset;
        const base = baseAsset;

        const {getFieldDecorator} = this.props.form;

        const marketFeeSymbol = (
            <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />
        );

        const quantitySymbol = (
            <AssetNameWrapper name={this.props.quoteAsset.get("symbol")} />
        );

        const totalSymbol = (
            <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />
        );

        const priceSymbol = (
            <div
                style={{
                    maxWidth: "110px",
                    display: "block",
                    overflow: "hidden",
                    textOverflow: "ellipsis"
                }}
            >
                <AssetNameWrapper name={this.props.baseAsset.get("symbol")} />/
                <AssetNameWrapper name={this.props.quoteAsset.get("symbol")} />
            </div>
        );

        const formItemProps = {
            labelCol: {span: 6},
            wrapperCol: {span: 18}
        };

        const actionRadio = getFieldDecorator("action", {
            initialValue: isBid
                ? SCALED_ORDER_ACTION_TYPES.BUY
                : SCALED_ORDER_ACTION_TYPES.SELL
        })(
            <Radio.Group>
                <Radio value={SCALED_ORDER_ACTION_TYPES.BUY}>
                    {counterpart.translate("scaled_orders.action.buy")}
                </Radio>
                <Radio value={SCALED_ORDER_ACTION_TYPES.SELL}>
                    {counterpart.translate("scaled_orders.action.sell")}
                </Radio>
            </Radio.Group>
        );

        const priceLowerInput = getFieldDecorator("priceLower", {
            validateFirst: true,
            validateTrigger: "onBlur",
            rules: [
                Validation.Rules.required(),
                Validation.Rules.number(),
                Validation.Rules.min({min: 0, name: "Price", higherThan: true})
            ]
        })(
            <Input
                placeholder="0.0"
                style={{width: "100%"}}
                autoComplete="off"
                addonAfter={priceSymbol}
            />
        );

        const formValues = this._getFormValues();

        const priceLower = Number((formValues && formValues.priceLower) || 0);

        const priceUpperInput = getFieldDecorator("priceUpper", {
            validateFirst: true,
            validateTrigger: "onBlur",
            rules: [
                Validation.Rules.required(),
                Validation.Rules.number(),
                Validation.Rules.min({
                    min: priceLower,
                    name: "Price",
                    higherThan: true
                })
            ]
        })(
            <Input
                placeholder="0.0"
                style={{width: "100%"}}
                autoComplete="off"
                addonAfter={priceSymbol}
            />
        );

        const feeCurrencySelect = getFieldDecorator("feeCurrency", {
            initialValue:
                ChainStore.getAsset("1.3.0") &&
                ChainStore.getAsset("1.3.0").get &&
                ChainStore.getAsset("1.3.0").get("symbol")
        })(
            <Select
                showSearch
                dropdownMatchSelectWidth={false}
                style={{minWidth: "80px", maxWidth: "120px"}}
            >
                {this.state.feeAssets &&
                    this.state.feeAssets.map &&
                    this.state.feeAssets.map(feeAsset => {
                        return (
{'fraction_non_alphanumeric': 0.11002361315492283, 'fraction_numerical': 0.0045172992026282464, 'mean_word_length': 1.5624342336022448, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1776806', 'n_tokens_mistral': 8045, 'n_tokens_neox': 7555, 'n_words': 1372}