<commit_before>/*
 * Copyright (C) 2015 <NAME>
 *
 * 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.
 */

package com.devbrackets.android.exomedia.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.devbrackets.android.exomedia.R;
import com.devbrackets.android.exomedia.event.EMMediaProgressEvent;
import com.devbrackets.android.exomedia.util.EMResourceUtil;
import com.devbrackets.android.exomedia.util.TimeFormatUtil;

/**
 * Provides playback controls for the EMVideoView on TV devices.
 */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class DefaultControlsLeanback extends DefaultControls {
    private static final int FAST_FORWARD_REWIND_AMOUNT = 10000; //10 seconds

    private ProgressBar progressBar;

    private ImageView rippleIndicator;

    private ImageButton fastForwardButton;
    private ImageButton rewindButton;

    private Drawable defaultRewindDrawable;
    private Drawable defaultFastForwardDrawable;

    private ButtonFocusChangeListener buttonFocusChangeListener = new ButtonFocusChangeListener();

    public DefaultControlsLeanback(Context context) {
        super(context);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void setup(Context context) {
        super.setup(context);
        playPauseButton.requestFocus();
    }

    @Override
    protected int getLayoutResource() {
        return R.layout.exomedia_video_controls_overlay_leanback;
    }

    /**
     * Sets the current video position, updating the seek bar
     * and the current time field
     *
     * @param position The position in milliseconds
     */
    @Override
    public void setPosition(long position) {
        currentTime.setText(TimeFormatUtil.formatMs(position));
        progressBar.setProgress((int) position);
    }

    /**
     * Sets the video duration in Milliseconds to display
     * at the end of the progress bar
     *
     * @param duration The duration of the video in milliseconds
     */
    @Override
    public void setDuration(long duration) {
        if (duration != progressBar.getMax()) {
            endTime.setText(TimeFormatUtil.formatMs(duration));
            progressBar.setMax((int) duration);
        }
    }

    /**
     * Performs the progress update on the current time field,
     * and the seek bar
     *
     * @param event The most recent progress
     */
    @Override
    public void setProgressEvent(EMMediaProgressEvent event) {
        progressBar.setSecondaryProgress((int) (progressBar.getMax() * event.getBufferPercentFloat()));
        progressBar.setProgress((int) event.getPosition());
        currentTime.setText(TimeFormatUtil.formatMs(event.getPosition()));
    }

    /**
     * Sets the state list drawable resource id to use for the Rewind button.
     * <b><em>NOTE:</em></b> The Rewind button is only shown on TV layouts
     *
     * @param resourceId The resourceId or 0
     */
    @Override
    public void setRewindImageResource(@DrawableRes int resourceId) {
        if (rewindButton == null) {
            return;
        }

        if (resourceId != 0) {
            rewindButton.setImageResource(resourceId);
        } else {
            rewindButton.setImageDrawable(defaultRewindDrawable);
        }
    }

    /**
     * Sets the state list drawable resource id to use for the Fast Forward button.
     * <b><em>NOTE:</em></b> The Fast Forward button is only shown on TV layouts
     *
     * @param resourceId The resourceId or 0
     */
    @Override
    public void setFastForwardImageResource(@DrawableRes int resourceId) {
        if (fastForwardButton == null) {
            return;
        }

        if (resourceId != 0) {
            fastForwardButton.setImageResource(resourceId);
        } else {
            fastForwardButton.setImageDrawable(defaultFastForwardDrawable);
        }
    }

    /**
     * Sets the button state for the Rewind button.  This will just
     * change the images specified with {@link #setRewindImageResource(int)},
     * or use the defaults if they haven't been set
     * </p>
     * This method will NOT re-add buttons that have previously been removed with
     * {@link #setRewindButtonRemoved(boolean)}.
     *
     * @param enabled If the Rewind button is enabled [default: false]
     */
    @Override
    public void setRewindButtonEnabled(boolean enabled) {
        if (rewindButton != null) {
            rewindButton.setEnabled(enabled);
        }
    }

    /**
     * Sets the button state for the Fast Forward button.  This will just
     * change the images specified with {@link #setFastForwardImageResource(int)},
     * or use the defaults if they haven't been set
     * </p>
     * This method will NOT re-add buttons that have previously been removed with
     * {@link #setFastForwardButtonRemoved(boolean)}.
     *
     * @param enabled If the Rewind button is enabled [default: false]
     */
    @Override
    public void setFastForwardButtonEnabled(boolean enabled) {
        if (fastForwardButton != null) {
            fastForwardButton.setEnabled(enabled);
        }
    }

    /**
     * Adds or removes the Rewind button.  This will change the visibility
     * of the button, if you want to change the enabled/disabled images see {@link #setRewindButtonEnabled(boolean)}
     *
     * @param removed If the Rewind button should be removed [default: true]
     */
    @Override
    public void setRewindButtonRemoved(boolean removed) {
        if (rewindButton != null) {
            rewindButton.setVisibility(removed ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * Adds or removes the FastForward button.  This will change the visibility
     * of the button, if you want to change the enabled/disabled images see {@link #setFastForwardButtonEnabled(boolean)}
     *
     * @param removed If the FastForward button should be removed [default: true]
     */
    @Override
    public void setFastForwardButtonRemoved(boolean removed) {
        if (fastForwardButton != null) {
            fastForwardButton.setVisibility(removed ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * Retrieves the view references from the xml layout
     */
    @Override
    protected void retrieveViews() {
        super.retrieveViews();
        progressBar = (ProgressBar) findViewById(R.id.exomedia_controls_video_progress);

        rewindButton = (ImageButton) findViewById(R.id.exomedia_controls_rewind_btn);
        fastForwardButton = (ImageButton) findViewById(R.id.exomedia_controls_fast_forward_btn);
        rippleIndicator = (ImageView) findViewById(R.id.exomedia_controls_leanback_ripple);
    }

    /**
     * Registers any internal listeners to perform the playback controls,
     * such as play/pause, next, and previous
     */
    @Override
    protected void registerListeners() {
        super.registerListeners();
        rewindButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onRewindClick();
            }
        });
        fastForwardButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onFastForwardClick();
            }
        });

        //Registers the buttons for focus changes in order to update the ripple selector
        previousButton.setOnFocusChangeListener(buttonFocusChangeListener);
        rewindButton.setOnFocusChangeListener(buttonFocusChangeListener);
        playPauseButton.setOnFocusChangeListener(buttonFocusChangeListener);
        fastForwardButton.setOnFocusChangeListener(buttonFocusChangeListener);
        nextButton.setOnFocusChangeListener(buttonFocusChangeListener);
    }

    /**
     * Updates the drawables used for the buttons to AppCompatTintDrawables
     */
    @Override
    protected void updateButtonDrawables() {
        super.updateButtonDrawables();

        defaultRewindDrawable = EMResourceUtil.tintList(getContext(), R.drawable.exomedia_ic_rewind_white, R.color.exomedia_default_controls_button_selector);
        rewindButton.setImageDrawable(defaultRewindDrawable);

        defaultFastForwardDrawable = EMResourceUtil.tintList(getContext(), R.drawable.exomedia_ic_fast_forward_white, R.color.exomedia_default_controls_button_selector);
        fastForwardButton.setImageDrawable(defaultFastForwardDrawable);
    }

    /**
     * Performs the functionality to rewind the current video by
     * {@value #FAST_FORWARD_REWIND_AMOUNT} milliseconds.
     */
    private void onRewindClick() {
        int newPosition = (int) videoView.getCurrentPosition() - FAST_FORWARD_REWIND_AMOUNT;
        if (newPosition < 0) {
            newPosition = 0;
        }

        performSeek(newPosition);
    }

    /**
     * Performs the functionality to fast forward the current video by
     * {@value #FAST_FORWARD_REWIND_AMOUNT} milliseconds.
     */
    private void onFastForwardClick() {
        int newPosition = (int) videoView.getCurrentPosition() + FAST_FORWARD_REWIND_AMOUNT;
        if (newPosition > progressBar.getMax()) {
            newPosition = progressBar.getMax();
        }

        performSeek(newPosition);
    }

    /**
     * Performs the functionality to inform any listeners that the video has been
     * seeked to the specified time.
     *
     * @param seekToTime The time to seek to in milliseconds
     */
    private void performSeek(int seekToTime) {
        if (seekCallbacks != null && seekCallbacks.onSeekEnded(seekToTime)) {
            return;
        }

        videoView.seekTo(seekToTime);
    }

    /**
     * A listener to monitor the selected button and move the ripple
     * indicator when the focus shifts.
     */
    private class ButtonFocusChangeListener implements OnFocusChangeListener {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            if (!hasFocus) {
                return;
            }

            //Performs the move animation
            int xDelta = getHorizontalDelta(view);
            rippleIndicator.startAnimation(new RippleTranslateAnimation(xDelta));
        }

        private int getHorizontalDelta(View selectedView) {
            int[] position = new int[2];
            selectedView.getLocationOnScreen(position);

            int x = position[0];
            rippleIndicator.getLocationOnScreen(position);

            return x - position[0];
        }
    }

    private class RippleTranslateAnimation extends TranslateAnimation implements Animation.AnimationListener {
        private static final long DURATION = 250;

        private int xDelta;

        public RippleTranslateAnimation(int xDelta) {
            super(0, xDelta, 0, 0);

            this.xDelta = xDelta;
            setDuration(DURATION);
            setAnimationListener(this);
        }

        @Override
        public void onAnimationStart(Animation animation) {
            //Purposefully left blank<commit_msg>Added a listener to key events to handle remote input<commit_after>/*
 * Copyright (C) 2015 <NAME>
 *
 * 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.
 */

package com.devbrackets.android.exomedia.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.devbrackets.android.exomedia.R;
import com.devbrackets.android.exomedia.event.EMMediaProgressEvent;
import com.devbrackets.android.exomedia.util.EMResourceUtil;
import com.devbrackets.android.exomedia.util.TimeFormatUtil;

/**
 * Provides playback controls for the EMVideoView on TV devices.
 */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class DefaultControlsLeanback extends DefaultControls {
    private static final int FAST_FORWARD_REWIND_AMOUNT = 10000; //10 seconds

    private ProgressBar progressBar;

    private ImageView rippleIndicator;

    private ImageButton fastForwardButton;
    private ImageButton rewindButton;

    private Drawable defaultRewindDrawable;
    private Drawable defaultFastForwardDrawable;

    private ButtonFocusChangeListener buttonFocusChangeListener = new ButtonFocusChangeListener();

    public DefaultControlsLeanback(Context context) {
        super(context);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DefaultControlsLeanback(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void setup(Context context) {
        super.setup(context);

        playPauseButton.requestFocus();
        setOnKeyListener(new RemoteKeyListener());
    }

    @Override
    protected int getLayoutResource() {
        return R.layout.exomedia_video_controls_overlay_leanback;
    }

    /**
     * Sets the current video position, updating the seek bar
     * and the current time field
     *
     * @param position The position in milliseconds
     */
    @Override
    public void setPosition(long position) {
        currentTime.setText(TimeFormatUtil.formatMs(position));
        progressBar.setProgress((int) position);
    }

    /**
     * Sets the video duration in Milliseconds to display
     * at the end of the progress bar
     *
     * @param duration The duration of the video in milliseconds
     */
    @Override
    public void setDuration(long duration) {
        if (duration != progressBar.getMax()) {
            endTime.setText(TimeFormatUtil.formatMs(duration));
            progressBar.setMax((int) duration);
        }
    }

    /**
     * Performs the progress update on the current time field,
     * and the seek bar
     *
     * @param event The most recent progress
     */
    @Override
    public void setProgressEvent(EMMediaProgressEvent event) {
        progressBar.setSecondaryProgress((int) (progressBar.getMax() * event.getBufferPercentFloat()));
        progressBar.setProgress((int) event.getPosition());
        currentTime.setText(TimeFormatUtil.formatMs(event.getPosition()));
    }

    /**
     * Sets the state list drawable resource id to use for the Rewind button.
     * <b><em>NOTE:</em></b> The Rewind button is only shown on TV layouts
     *
     * @param resourceId The resourceId or 0
     */
    @Override
    public void setRewindImageResource(@DrawableRes int resourceId) {
        if (rewindButton == null) {
            return;
        }

        if (resourceId != 0) {
            rewindButton.setImageResource(resourceId);
        } else {
            rewindButton.setImageDrawable(defaultRewindDrawable);
        }
    }

    /**
     * Sets the state list drawable resource id to use for the Fast Forward button.
     * <b><em>NOTE:</em></b> The Fast Forward button is only shown on TV layouts
     *
     * @param resourceId The resourceId or 0
     */
    @Override
    public void setFastForwardImageResource(@DrawableRes int resourceId) {
        if (fastForwardButton == null) {
            return;
        }

        if (resourceId != 0) {
            fastForwardButton.setImageResource(resourceId);
        } else {
            fastForwardButton.setImageDrawable(defaultFastForwardDrawable);
        }
    }

    /**
     * Sets the button state for the Rewind button.  This will just
     * change the images specified with {@link #setRewindImageResource(int)},
     * or use the defaults if they haven't been set
     * </p>
     * This method will NOT re-add buttons that have previously been removed with
     * {@link #setRewindButtonRemoved(boolean)}.
     *
     * @param enabled If the Rewind button is enabled [default: false]
     */
    @Override
    public void setRewindButtonEnabled(boolean enabled) {
        if (rewindButton != null) {
            rewindButton.setEnabled(enabled);
        }
    }

    /**
     * Sets the button state for the Fast Forward button.  This will just
     * change the images specified with {@link #setFastForwardImageResource(int)},
     * or use the defaults if they haven't been set
     * </p>
     * This method will NOT re-add buttons that have previously been removed with
     * {@link #setFastForwardButtonRemoved(boolean)}.
     *
     * @param enabled If the Rewind button is enabled [default: false]
     */
    @Override
    public void setFastForwardButtonEnabled(boolean enabled) {
        if (fastForwardButton != null) {
            fastForwardButton.setEnabled(enabled);
        }
    }

    /**
     * Adds or removes the Rewind button.  This will change the visibility
     * of the button, if you want to change the enabled/disabled images see {@link #setRewindButtonEnabled(boolean)}
     *
     * @param removed If the Rewind button should be removed [default: true]
     */
    @Override
    public void setRewindButtonRemoved(boolean removed) {
        if (rewindButton != null) {
            rewindButton.setVisibility(removed ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * Adds or removes the FastForward button.  This will change the visibility
     * of the button, if you want to change the enabled/disabled images see {@link #setFastForwardButtonEnabled(boolean)}
     *
     * @param removed If the FastForward button should be removed [default: true]
     */
    @Override
    public void setFastForwardButtonRemoved(boolean removed) {
        if (fastForwardButton != null) {
            fastForwardButton.setVisibility(removed ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * Retrieves the view references from the xml layout
     */
    @Override
    protected void retrieveViews() {
        super.retrieveViews();
        progressBar = (ProgressBar) findViewById(R.id.exomedia_controls_video_progress);

        rewindButton = (ImageButton) findViewById(R.id.exomedia_controls_rewind_btn);
        fastForwardButton = (ImageButton) findViewById(R.id.exomedia_controls_fast_forward_btn);
        rippleIndicator = (ImageView) findViewById(R.id.exomedia_controls_leanback_ripple);
    }

    /**
     * Registers any internal listeners to perform the playback controls,
     * such as play/pause, next, and previous
     */
    @Override
    protected void registerListeners() {
        super.registerListeners();
        rewindButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onRewindClick();
            }
        });
        fastForwardButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onFastForwardClick();
            }
        });

        //Registers the buttons for focus changes in order to update the ripple selector
        previousButton.setOnFocusChangeListener(buttonFocusChangeListener);
        rewindButton.setOnFocusChangeListener(buttonFocusChangeListener);
        playPauseButton.setOnFocusChangeListener(buttonFocusChangeListener);
        fastForwardButton.setOnFocusChangeListener(buttonFocusChangeListener);
        nextButton.setOnFocusChangeListener(buttonFocusChangeListener);
    }

    /**
     * Updates the drawables used for the buttons to AppCompatTintDrawables
     */
    @Override
    protected void updateButtonDrawables() {
        super.updateButtonDrawables();

        defaultRewindDrawable = EMResourceUtil.tintList(getContext(), R.drawable.exomedia_ic_rewind_white, R.color.exomedia_default_controls_button_selector);
        rewindButton.setImageDrawable(defaultRewindDrawable);

        defaultFastForwardDrawable = EMResourceUtil.tintList(getContext(), R.drawable.exomedia_ic_fast_forward_white, R.color.exomedia_default_controls_button_selector);
        fastForwardButton.setImageDrawable(defaultFastForwardDrawable);
    }

    /**
     * Performs the functionality to rewind the current video by
     * {@value #FAST_FORWARD_REWIND_AMOUNT} milliseconds.
     */
    private void onRewindClick() {
        int newPosition = (int) videoView.getCurrentPosition() - FAST_FORWARD_REWIND_AMOUNT;
        if (newPosition < 0) {
            newPosition = 0;
        }

        performSeek(newPosition);
    }

    /**
     * Performs the functionality to fast forward the current video by
     * {@value #FAST_FORWARD_REWIND_AMOUNT} milliseconds.
     */
    private void onFastForwardClick() {
        int newPosition = (int) videoView.getCurrentPosition() + FAST_FORWARD_REWIND_AMOUNT;
        if (newPosition > progressBar.getMax()) {
            newPosition = progressBar.getMax();
        }

        performSeek(newPosition);
    }

    /**
     * Performs the functionality to inform any listeners that the video has been
     * seeked to the specified time.
     *
     * @param seekToTime The time to seek to in milliseconds
     */
    private void performSeek(int seekToTime) {
        if (seekCallbacks != null && seekCallbacks.onSeekEnded(seekToTime)) {
            return;
        }

        videoView.seekTo(seekToTime);
    }

    /**
     * A listener to monitor the selected button and move the ripple
     * indicator when the focus shifts.
     */
    private class ButtonFocusChangeListener implements OnFocusChangeListener {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            if (!hasFocus) {
                return;
            }

            //Performs the move animation
            int xDelta = getHorizontalDelta(view);
            rippleIndicator.startAnimation(new RippleTranslateAnimation(xDelta));
        }

        private int getHorizontalDelta(View selectedView) {
            int[] position = new int[2];
            selectedView.getLocationOnScreen(position);

            int x = position[0];
            rippleIndicator.getLocationOnScreen(position);

            return x - position[0];
        }
    }

    /**
     * A listener to catch the key events so that we can correctly perform the
     * playback functionality and to hide/show the controls
     */
    private class RemoteKeyListener implements OnKeyListener {
        @Override
        public boolean onKey(View view, int keyCode, KeyEvent event) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_BACK:
                    if (isVisible) {
                        hideDelayed(0);
                        return true;
                    }
                    break;

                case KeyEvent.KEYCODE_DPAD_UP:
                    show();
                    return true;

                case KeyEvent.KEYCODE_DPAD_DOWN:
                    hideDelayed(0);
                    return true;

                case KeyEvent.KEYCODE_DPAD_LEFT:
                    show();
                    break;

                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    show();
                    break;

                case KeyEvent.KEYCODE_DPAD_CENTER:
                    show();
                    break;

                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                    onPlayPauseClick();
                    return true;

                case KeyEvent.KEYCODE_MEDIA_PLAY:
                    if (!videoView.isPlaying()) {
                        videoView.start();
                        return true;
                    }
                    break;

                case KeyEvent.KEYCODE_MEDIA_PAUSE:
                    if (videoView.isPlaying()) {
                        videoView.pause();
                        return true;
                    }
                    break;

                case KeyEvent.KEYCODE_MEDIA_NEXT:
                    onNextClick();
                    return true;

                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                    onPreviousClick();
                    return true;

                case KeyEvent.KEYCODE_MEDIA_REWIND:
                    onRewindClick();
                    return true;

                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
                    onFastForwardClick();
                    return true;
            }

            return false;
        }
    }

    private class RippleTranslateAnimation extends TranslateAnimation implements Animation.AnimationListener {
        private static final long DURATION = 250;

        private int xDelta;

        public RippleTranslateAnimation(int xDelta) {
            super(0, xDelta, 0, 0);

            this.xDelta = xDelta;
            setDuration(DURATION);
            setAnimationListener(this);
        }

        @Override
        public void onAnimationStart(Animation animation) {
            //Purposefully left blank
{'fraction_non_alphanumeric': 0.07741022202354343, 'fraction_numerical': 0.0023096408880941737, 'mean_word_length': 2.536890645586298, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, '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': '263932', 'n_tokens_mistral': 7137, 'n_tokens_neox': 6830, 'n_words': 1912}