<commit_before>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";

export default class FacetFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            // selectedFacet is a prop to keep the chance in the future to preselect fields
            selectedFacet: {
                type: Object
            }
        }
    }

    _init(){
        this._prefix = "sf-" + UtilsNew.randomString(6) + "_";

    }

    updated(changedProperties) {
        if(changedProperties.has("selectedFacet")) {
            this.selectedFacetObserver();
        }
    }

    selectedFacetObserver() {
        /**
         * Helper for formatting the list of facets to show in opencga-active-filters
         */
        const _valueFormatter = (k, v) => {
            let str = "";
            if (v.fn && (v.fn === "Avg" || v.fn === "Percentile")) {
                str = v.fn + "(" + k + ")";
            } else {
                str = k + (v.value ? "[" + v.value + "]" : "");
            }
            if (v.nested) {
                str += ">>" + ((v.nested.fn && (v.nested.fn === "Avg" || v.nested.fn === "Percentile")) ? v.nested.fn + "(" + v.nested.facet + ")" : v.nested.facet + (v.nested.value ? "[" + v.nested.value + "]" : ""));
            }
            return str;
        };
        if (Object.keys(this.selectedFacet).length) {
            // Object property spreading cannot be used here as it creates an Object with numeric indexes in Chrome 78...
            this.selectedFacetFormatted = Object.assign({}, ...Object.keys(this.selectedFacet).map(k => ({
                [k]: {
                    ...this.selectedFacet[k],
                    formatted: _valueFormatter(k, this.selectedFacet[k])
                }
            })));
        } else {
            this.selectedFacetFormatted = {};
        }
        const event = new CustomEvent("facetQueryChange", {
            detail: {
                value: this.selectedFacetFormatted
            }
        });
        this.dispatchEvent(event);
        this.requestUpdate();
    }

    addDefaultFacet() {
        for (const defaultFacetId of this.config.default) {
            const facet = defaultFacetId.split(">>");
            //console.log(facet);
            // in case of nested facets
            if (facet.length > 1) {
                const mainFacet = this._recFind(this.config.sections, facet[0]);
                const nestedFacet = this._recFind(this.config.sections, facet[1]);
                //console.log("nestedFacet", nestedFacet);
                this.selectedFacet[facet[0]] = {
                    ...mainFacet,
                    value: mainFacet?.defaultValue ?? "",
                    nested: {...nestedFacet, facet: facet[1], value: nestedFacet.defaultValue || ""}
                };
            } else {
                const mainFacet = this._recFind(this.config.sections, facet[0]);
                this.selectedFacet[defaultFacetId] = {...mainFacet, value: mainFacet?.defaultValue ?? ""};
            }
        }
        this.selectedFacet = {...this.selectedFacet};
    }

    async onFacetFieldChange(e) {
        // select-field-filter fires a filterChange event with all the selected values. Here we need here just the new selected (deselected) item, so we compute the difference between the 2 sets
        const currentSelectionNames = e.detail.value ? e.detail.value.split(",") : [];
        // compute the symmetric difference between this.selectedFacet and currentSelectionNames
        const differences = Object.keys(this.selectedFacet)
            .filter(a => !currentSelectionNames.includes(a))
            .concat(currentSelectionNames.filter(name => !Object.keys(this.selectedFacet).includes(name)));

        // the difference involves one item at a time
        if (differences.length > 1) console.error("Difference error!", this.selectedFacet, currentSelectionNames);

        const difference = differences[0];
        // addition
        if (currentSelectionNames.length > Object.keys(this.selectedFacet).length) {
            console.log("addition of", difference);
            // Array.find() cannot be nested.. let newField = this.config.sections.find(field => field.fields ? field.fields.find(nested => nested === difference) : field.name === difference);
            // console.log(this.config.sections, difference)
            const newField = this._recFind(this.config.sections, difference);
            // console.log("newField", newField)
            this.selectedFacet[difference] = {...newField, value: newField && newField.defaultValue ? newField.defaultValue : ""};
            await this.requestUpdate();
            $(".bootstrap-select", this).selectpicker();
        } else {
            console.log("deletion of", difference);
            // deletion
            delete this.selectedFacet[difference];
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onFacetValueChange(e) {
        // console.log("onFacetValueChange",e);
        const id = e.target.dataset.id;
        // this.selectedFacet = {...this.selectedFacet, [id]: (e.target.value.trim() ? e.target.value : "")};
        this.selectedFacet[id].value = e.target.value.trim() ? e.target.value : "";
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onFacetSelectChange(e) {
        // console.log("onFacetSelectChange",e);
        const id = e.target.dataset.id;
        // this.selectedFacet = {...this.selectedFacet, [id]: (e.target.value.trim() ? e.target.value : "")};
        this.selectedFacet[id].value = e.detail.value ? e.detail.value : "";
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onFacetFnChange(e) {
        const value = e.detail.value;
        const facet = e.target.dataset.facet;
        if (value && (value === "Avg" || value === "Percentile")) {
            this.selectedFacet[facet]["fn"] = value;
            this.querySelector("#" + this._prefix + facet + "_text").disabled = true;
        } else {
            delete this.selectedFacet[facet]["fn"];
            this.querySelector("#" + this._prefix + facet + "_text").disabled = false;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    toggleCollapse(e) {
        $(e.target.dataset.collapse).collapse("toggle");
    }

    onNestedFacetValueChange(e) {
        this.selectedFacet[e.target.dataset.parentFacet].nested.value = e.target.value || e.detail.value; //e.detail.value handles <select-field-filter> change events, in which e.target.value is an empty string
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onNestedFacetFieldChange(e, parent) {
        const selected = e.detail.value;
        if (selected) {
            const newField = this._recFind(this.config.sections, selected);
            this.selectedFacet[parent].nested = {...newField, facet: selected, value: newField.defaultValue || ""};
        } else {
            delete this.selectedFacet[parent].nested;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onNestedFacetFnChange(e) {
        const value = e.detail.value;
        const facet = e.target.dataset.parentFacet;
        console.log("nestedFacetFNCHANGE", "#" + this._prefix + facet + "_NestedValue");
        if (value && (value === "Avg" || value === "Percentile")) {
            if (this.selectedFacet[facet].nested) {
                this.selectedFacet[facet].nested.fn = value;
                this.querySelector("#" + this._prefix + facet + "_NestedValue").disabled = true;
            } else {
                console.error("function selected before facet!");
            }
        } else {
            this.querySelector("#" + this._prefix + facet + "_NestedValue").disabled = false;
            delete this.selectedFacet[facet].nested.fn;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    _recFind(array, value) {
        for (const f of array) {
            if (f.fields) {
                const r = this._recFind(f.fields, value);
                if (r) return r;
            } else {
                if (f.id === value) {
                    // console.log("found", f);
                    return f;
                }
            }
        }
    }

    renderField(facet) {
        const renderNestedFieldWrapper = facet => html`
                    <!-- nested facet -->
                    <div class="row facet-row nested">
                        <div class="col-md-12 text-center">
                            <a class="btn btn-small collapsed" role="button" data-collapse="#${facet.id}_nested" @click="${this.toggleCollapse}"> <i class="fas fa-arrow-alt-circle-down"></i> Nested Facet (optional) </a>
                            <div class="collapse ${this.selectedFacet[facet.id].nested ? "in" : ""}" id="${facet.id}_nested"> 
                                <div class="">
                                    <select-field-filter .data="${this.config.sections.map(section => ({...section, fields: section.fields.map(item => ({...item, disabled: item.id === facet.id})) }))}" .value=${this.selectedFacet[facet.id].nested ? this.selectedFacet[facet.id].nested.id : null} @filterChange="${e => this.onNestedFacetFieldChange(e, facet.id)}"></select-field-filter>
                                    <div class="row facet-row nested">
                                        ${this.renderNestedField(this.selectedFacet[facet.id].nested, facet.id)}
                                    </div>                                
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- /nested facet -->
        `;

        switch (facet.type) {
            case "category":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <select-field-filter ?multiple="${facet.multiple === undefined || facet.multiple}" .data="${facet.allowedValues}" .value="${facet.defaultValue ? facet.defaultValue : ""}" id="${facet.id}_Select" data-id="${facet.id}" @filterChange="${this.onFacetSelectChange}"></select-field-filter>
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                    `;
            case "number":
            case "integer":
            case "float":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" placeholder="Include values or set range" id="${this._prefix}${facet.id}_text" data-id="${facet.id}" .value="${facet.value || ""}" @input="${this.onFacetValueChange}" />
                        </div>
                        <div class="col-md-6">
                            <select-field-filter .data="${["Range", "Avg", "Percentile"]}" .value="${"Range"}" id="${this._prefix}${facet.id}_FnSelect" data-facet="${facet.id}" @filterChange="${this.onFacetFnChange}"></select-field-filter>
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                `;
            case "string":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <input type="text" class="form-control" placeholder="Include values" @input="${this.onFacetValueChange}" data-id="${facet.id}" type="text" .value="${facet.defaultValue ? facet.defaultValue : ""}" id="${facet.id}_NestedFnSelect"  />
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                `;
            case "boolean":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <fieldset>
                                <div class="switch-toggle text-white">
                                    <input id="${this._prefix}-true" class="form-group-sm" type="radio" name="${this._prefix}-options" value="True" data-id="${facet.id}" @change="${this.onFacetValueChange}">
                                    <label for="${this._prefix}-true"><span class="small">True</span></label>
                                    <input id="${this._prefix}-false" class="form-group-sm" type="radio" name="${this._prefix}-options" value="False" data-id="${facet.id}" @change="${this.onFacetValueChange}">
                                    <label for="${this._prefix}-false"><span class="small">False</span></label>
                                    <a class="btn btn-primary ripple"></a>
                                </div>
                            </fieldset>
                        </div>
                    </div>
                    `;
            default:
                console.log("no type recognized", facet)<commit_msg>facet-filter bugfix for range fields in progress #109<commit_after>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";

export default class FacetFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            // selectedFacet is a prop to keep the chance in the future to preselect fields
            selectedFacet: {
                type: Object
            }
        }
    }

    _init(){
        this._prefix = "sf-" + UtilsNew.randomString(6) + "_";

    }

    updated(changedProperties) {
        if(changedProperties.has("selectedFacet")) {
            this.selectedFacetObserver();
        }
    }

    selectedFacetObserver() {
        /**
         * Helper for formatting the list of facets to show in opencga-active-filters
         */
        const _valueFormatter = (k, v) => {
            let str = "";
            if (v.fn && (v.fn === "Avg" || v.fn === "Percentile")) {
                str = v.fn + "(" + k + ")";
            } else {
                str = k + (v.value ? "[" + v.value + "]" : "");
            }
            if (v.nested) {
                str += ">>" + ((v.nested.fn && (v.nested.fn === "Avg" || v.nested.fn === "Percentile")) ? v.nested.fn + "(" + v.nested.facet + ")" : v.nested.facet + (v.nested.value ? "[" + v.nested.value + "]" : ""));
            }
            return str;
        };
        if (Object.keys(this.selectedFacet).length) {
            // Object property spreading cannot be used here as it creates an Object with numeric indexes in Chrome 78...
            this.selectedFacetFormatted = Object.assign({}, ...Object.keys(this.selectedFacet).map(k => ({
                [k]: {
                    ...this.selectedFacet[k],
                    formatted: _valueFormatter(k, this.selectedFacet[k])
                }
            })));
        } else {
            this.selectedFacetFormatted = {};
        }
        const event = new CustomEvent("facetQueryChange", {
            detail: {
                value: this.selectedFacetFormatted
            }
        });
        UtilsNew.initTooltip(this);
        this.dispatchEvent(event);
        this.requestUpdate();
    }

    addDefaultFacet() {
        for (const defaultFacetId of this.config.default) {
            const facet = defaultFacetId.split(">>");
            // in case of nested facets
            if (facet.length > 1) {
                const mainFacet = this._recFind(this.config.sections, facet[0]);

                const nestedFacet = this._recFind(this.config.sections, facet[1]);
                //console.log("nestedFacet", nestedFacet);
                this.selectedFacet[facet[0]] = {
                    ...mainFacet,
                    value: mainFacet?.defaultValue ?? "",
                    nested: {...nestedFacet, facet: facet[1], value: nestedFacet.defaultValue || ""}
                };
            } else {
                //discriminate between range fiels with default value and all the others
                let range = [...facet[0].matchAll(/(\w+)\[(\d+..\d+)](:\d+)?/gi)];
                if(range.length) {
                    const [r, facetKey, value, step] = range[0];
                    const mainFacet = this._recFind(this.config.sections, facetKey);
                    this.selectedFacet[facetKey] = {...mainFacet, value: value};
                } else {
                    const mainFacet = this._recFind(this.config.sections, facet[0]);
                    this.selectedFacet[defaultFacetId] = {...mainFacet, value: mainFacet?.defaultValue ?? ""};

                }
            }
        }
        this.selectedFacet = {...this.selectedFacet};
        UtilsNew.initTooltip(this);
    }

    async onFacetFieldChange(e) {
        // select-field-filter fires a filterChange event with all the selected values. Here we need here just the new selected (deselected) item, so we compute the difference between the 2 sets
        const currentSelectionNames = e.detail.value ? e.detail.value.split(",") : [];
        // compute the symmetric difference between this.selectedFacet and currentSelectionNames
        const differences = Object.keys(this.selectedFacet)
            .filter(a => !currentSelectionNames.includes(a))
            .concat(currentSelectionNames.filter(name => !Object.keys(this.selectedFacet).includes(name)));

        // the difference involves one item at a time
        if (differences.length > 1) console.error("Difference error!", this.selectedFacet, currentSelectionNames);

        const difference = differences[0];
        // addition
        if (currentSelectionNames.length > Object.keys(this.selectedFacet).length) {
            console.log("addition of", difference);
            // Array.find() cannot be nested.. let newField = this.config.sections.find(field => field.fields ? field.fields.find(nested => nested === difference) : field.name === difference);
            // console.log(this.config.sections, difference)
            const newField = this._recFind(this.config.sections, difference);
            // console.log("newField", newField)
            this.selectedFacet[difference] = {...newField, value: newField && newField.defaultValue ? newField.defaultValue : ""};
            await this.requestUpdate();
            $(".bootstrap-select", this).selectpicker();
        } else {
            console.log("deletion of", difference);
            // deletion
            delete this.selectedFacet[difference];
        }
        this.selectedFacet = {...this.selectedFacet};
        UtilsNew.initTooltip(this);
        //await this.requestUpdate();

    }

    onFacetValueChange(e) {
        // console.log("onFacetValueChange",e);
        const id = e.target.dataset.id;
        // this.selectedFacet = {...this.selectedFacet, [id]: (e.target.value.trim() ? e.target.value : "")};
        this.selectedFacet[id].value = e.target.value.trim() ? e.target.value : "";
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onFacetSelectChange(e) {
        // console.log("onFacetSelectChange",e);
        const id = e.target.dataset.id;
        // this.selectedFacet = {...this.selectedFacet, [id]: (e.target.value.trim() ? e.target.value : "")};
        this.selectedFacet[id].value = e.detail.value ? e.detail.value : "";
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onFacetFnChange(e) {
        const value = e.detail.value;
        const facet = e.target.dataset.facet;
        if (value && (value === "Avg" || value === "Percentile")) {
            this.selectedFacet[facet]["fn"] = value;
            this.querySelector("#" + this._prefix + facet + "_text").disabled = true;
        } else {
            delete this.selectedFacet[facet]["fn"];
            this.querySelector("#" + this._prefix + facet + "_text").disabled = false;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    toggleCollapse(e) {
        $(e.target.dataset.collapse).collapse("toggle");
    }

    onNestedFacetValueChange(e) {
        this.selectedFacet[e.target.dataset.parentFacet].nested.value = e.target.value || e.detail.value; //e.detail.value handles <select-field-filter> change events, in which e.target.value is an empty string
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onNestedFacetFieldChange(e, parent) {
        const selected = e.detail.value;
        if (selected) {
            const newField = this._recFind(this.config.sections, selected);
            this.selectedFacet[parent].nested = {...newField, facet: selected, value: newField.defaultValue || ""};
        } else {
            delete this.selectedFacet[parent].nested;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    onNestedFacetFnChange(e) {
        const value = e.detail.value;
        const facet = e.target.dataset.parentFacet;
        console.log("nestedFacetFNCHANGE", "#" + this._prefix + facet + "_NestedValue");
        if (value && (value === "Avg" || value === "Percentile")) {
            if (this.selectedFacet[facet].nested) {
                this.selectedFacet[facet].nested.fn = value;
                this.querySelector("#" + this._prefix + facet + "_NestedValue").disabled = true;
            } else {
                console.error("function selected before facet!");
            }
        } else {
            this.querySelector("#" + this._prefix + facet + "_NestedValue").disabled = false;
            delete this.selectedFacet[facet].nested.fn;
        }
        this.selectedFacet = {...this.selectedFacet};
        this.requestUpdate();
    }

    _recFind(array, value) {
        for (const f of array) {
            if (f.fields) {
                const r = this._recFind(f.fields, value);
                if (r) return r;
            } else {
                if (f.id === value) {
                    // console.log("found", f);
                    return f;
                }
            }
        }
    }

    renderField(facet) {
        const renderNestedFieldWrapper = facet => html`
                    <!-- nested facet -->
                    <div class="row facet-row nested">
                        <div class="col-md-12 text-center">
                            <a class="btn btn-small collapsed" role="button" data-collapse="#${facet.id}_nested" @click="${this.toggleCollapse}"> <i class="fas fa-arrow-alt-circle-down"></i> Nested Facet (optional) </a>
                            <div class="collapse ${this.selectedFacet[facet.id].nested ? "in" : ""}" id="${facet.id}_nested"> 
                                <div class="">
                                    <select-field-filter .data="${this.config.sections.map(section => ({...section, fields: section.fields.map(item => ({...item, disabled: item.id === facet.id}))}))}" .value=${this.selectedFacet[facet.id].nested ? this.selectedFacet[facet.id].nested.id : null} @filterChange="${e => this.onNestedFacetFieldChange(e, facet.id)}"></select-field-filter>
                                    <div class="row facet-row nested">
                                        ${this.renderNestedField(this.selectedFacet[facet.id].nested, facet.id)}
                                    </div>                                
                                </div>
                            </div>
                        </div>
                    </div>
                    <!-- /nested facet -->
        `;

        switch (facet.type) {
            case "category":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <select-field-filter ?multiple="${facet.multiple === undefined || facet.multiple}" .data="${facet.allowedValues}" .value="${facet.defaultValue ? facet.defaultValue : ""}" id="${facet.id}_Select" data-id="${facet.id}" @filterChange="${this.onFacetSelectChange}"></select-field-filter>
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                    `;
            case "number":
            case "integer":
            case "float":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" placeholder="Include values or set range" id="${this._prefix}${facet.id}_text" data-id="${facet.id}" .value="${facet.value || ""}" @input="${this.onFacetValueChange}" />
                        </div>
                        <div class="col-md-6">
                            <select-field-filter .data="${["Range", "Avg", "Percentile"]}" .value="${"Range"}" id="${this._prefix}${facet.id}_FnSelect" data-facet="${facet.id}" @filterChange="${this.onFacetFnChange}"></select-field-filter>
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                `;
            case "string":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <input type="text" class="form-control" placeholder="Include values" @input="${this.onFacetValueChange}" data-id="${facet.id}" type="text" .value="${facet.value ?? facet.defaultValue ?? ""}" id="${facet.id}_NestedFnSelect"  />
                        </div>
                    </div>
                    ${renderNestedFieldWrapper(facet)}
                `;
            case "boolean":
                return html`
                    <div class="row facet-row">
                        <div class="col-md-12">
                            <fieldset>
                                <div class="switch-toggle text-white">
                                    <input id="${this._prefix}-true" class="form-group-sm" type="radio" name="${this._prefix}-options" value="True" data-id="${facet.id}" @change="${this.onFacetValueChange}">
                                    <label for="${this._prefix}-true"><span class="small">True</span></label>
                                    <input id="${this._prefix}-false" class="form-group-sm" type="radio" name="${this._prefix}-options" value="False" data-id="${facet.id}" @change="${this.onFacetValueChange}">
                                    <label for="${this._prefix}-false"><span class="small">False</span></label>
                                    <a class="btn btn-primary ripple"></a>
                                </div>
                            </fieldset>
                        </div>
                    </div>
                    `;
            default:
                console.log("no type recognized", facet)
{'fraction_non_alphanumeric': 0.14464509831264816, 'fraction_numerical': 0.0025449728071398688, 'mean_word_length': 1.7452387788305102, 'pattern_counts': {'":': 12, '<': 121, '<?xml version=': 0, '>': 155, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3825025', 'n_tokens_mistral': 7879, 'n_tokens_neox': 7560, 'n_words': 1555}