<commit_before>import re
from django.shortcuts import redirect
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from django.core.exceptions import PermissionDenied
from django.core.paginator import Paginator
from django.conf import settings
from django.contrib import messages
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
from django.template import loader
from django.utils import timezone
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import ensure_csrf_cookie
from time import time
from urllib import parse as urlparse
import simplejson as json
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q
from .models import FileCategory, Project, ProjectFile, ProjectPosition, UserAlert, VolunteerRelation, Group, Event, \
    ProjectRelationship, Testimonial, ProjectFavorite
from .sitemaps import SitemapPages
from .caching.cache import ProjectSearchTagsCache
from common.caching.cache import Cache
from common.helpers.collections import flatten, count_occurrences
from common.helpers.db import unique_column_values
from common.helpers.s3 import presign_s3_upload, user_has_permission_for_s3_file, delete_s3_file
from common.helpers.tags import get_tags_by_category,get_tag_dictionary
from common.helpers.form_helpers import is_co_owner_or_staff, is_co_owner, is_co_owner_or_owner, is_creator_or_staff, is_creator
from .forms import ProjectCreationForm, EventCreationForm, GroupCreationForm
from common.helpers.qiqo_chat import get_user_qiqo_iframe
from democracylab.models import Contributor, get_request_contributor
from common.models.tags import Tag
from common.helpers.constants import FrontEndSection, TagCategory
from democracylab.emails import send_to_project_owners, send_to_project_volunteer, HtmlEmailTemplate, send_volunteer_application_email, \
    send_volunteer_conclude_email, notify_project_owners_volunteer_renewed_email, notify_project_owners_volunteer_concluded_email, \
    notify_project_owners_project_approved, contact_democracylab_email, send_to_group_owners, send_group_project_invitation_email, \
    notify_group_owners_group_approved, notify_event_owners_event_approved
from civictechprojects.helpers.context_preload import context_preload
from civictechprojects.helpers.projects.annotations import apply_project_annotations
from common.helpers.front_end import section_url, get_page_section, get_clean_url, redirect_from_deprecated_url
from common.helpers.redirectors import redirect_by, InvalidArgumentsRedirector, DirtyUrlsRedirector, DeprecatedUrlsRedirector
from common.helpers.user_helpers import get_my_projects, get_my_groups, get_my_events, get_user_context
from django.views.decorators.cache import cache_page
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
import requests


def get_tag_counts(category=None, event=None, group=None):
    queryset = get_tags_by_category(category) if category is not None else Tag.objects.all()
    activetagdict = ProjectSearchTagsCache.get(event=event, group=group)
    querydict = {tag.tag_name: tag for tag in queryset}
    resultdict = {}

    for slug in querydict.keys():
        resultdict[slug] = Tag.hydrate_tag_model(querydict[slug])
        resultdict[slug]['num_times'] = activetagdict[slug] if slug in activetagdict else 0
    return list(resultdict.values())


def tags(request):
    url_parts = request.GET.urlencode()
    query_terms = urlparse.parse_qs(url_parts, keep_blank_values=0, strict_parsing=0)
    category = query_terms.get('category')[0] if 'category' in query_terms else None
    queryset = get_tags_by_category(category) if category is not None else Tag.objects.all()
    tags_result = list(map(lambda tag: Tag.hydrate_tag_model(tag), queryset))
    return JsonResponse(tags_result, safe=False)


@cache_page(1200) #cache duration in seconds, cache_page docs: https://docs.djangoproject.com/en/2.1/topics/cache/#the-per-view-cache
def group_tags_counts(request):
    # Get all groups
    all_groups = Group.objects.all()
    # Get Groups issue areas
    group_issues = list(map(lambda group: group.get_project_issue_areas(with_counts=False), all_groups))
    # Count up instances of tags
    group_issues_counts = count_occurrences(flatten(group_issues))
    issue_tags = {}
    for issue_tag in group_issues_counts.keys():
        issue_tags[issue_tag] = Tag.hydrate_tag_model(Tag.get_by_name(issue_tag))
        issue_tags[issue_tag]['num_times'] = group_issues_counts[issue_tag]
    return JsonResponse(list(issue_tags.values()), safe=False)


def to_rows(items, width):
    rows = [[]]
    row_number = 0
    column_number = 0
    for item in items:
        rows[row_number].append(item)
        column_number += 1
        if column_number >= width:
            column_number = 0
            rows.append([])
            row_number += 1
    return rows


def to_tag_map(tags):
    tag_map = ((tag.tag_name, tag.display_name) for tag in tags)
    return list(tag_map)

# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def group_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    group = GroupCreationForm.create_or_edit_group(request, None)
    return JsonResponse(group.hydrate_to_json())


def group_edit(request, group_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    group = None
    try:
        group = GroupCreationForm.create_or_edit_group(request, group_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(group.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutGroup, {'id': group_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def group_delete(request, group_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        GroupCreationForm.delete_group(request, group_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_group(request, group_id):
    group = Group.objects.get(id=group_id)

    if group is not None:
        if group.is_searchable or is_creator_or_staff(get_request_contributor(request), group):
            return JsonResponse(group.hydrate_to_json())
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_group(request, group_id):
    group = Group.objects.get(id=group_id)
    user = get_request_contributor(request)

    if group is not None:
        if user.is_staff:
            group.is_searchable = True
            group.save()
            # SitemapPages.update()
            ProjectSearchTagsCache.refresh(event=None, group=group)
            notify_group_owners_group_approved(group)
            messages.success(request, 'Group Approved')

            return redirect(section_url(FrontEndSection.AboutGroup, {'id': str(group.id)}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def event_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    event = None
    try:
        event = EventCreationForm.create_or_edit_event(request, None)
    except PermissionDenied:
        return HttpResponseForbidden()
    return JsonResponse(event.hydrate_to_json())


def event_edit(request, event_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    event = None
    try:
        event = EventCreationForm.create_or_edit_event(request, event_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(event.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutEvent, {'id': event_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def event_delete(request, event_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        EventCreationForm.delete_event(request, event_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_event(request, event_id):
    try:
        event = Event.get_by_id_or_slug(event_id)
        if event_id.isnumeric() and event.is_private and not is_creator_or_staff(get_request_contributor(request), event):
            # Don't let non-admins/non-owners load a private event by numeric id
            raise PermissionDenied()
    except PermissionDenied:
        return HttpResponseForbidden()

    return JsonResponse(event.hydrate_to_json()) if event else HttpResponse(status=404)


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def project_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    project = ProjectCreationForm.create_or_edit_project(request, None)
    return JsonResponse(project.hydrate_to_json())


def project_edit(request, project_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    try:
        project = ProjectCreationForm.create_or_edit_project(request, project_id)
        # TODO:
        # update_cached_project_url(project_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(project.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def project_delete(request, project_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        ProjectCreationForm.delete_project(request, project_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_project(request, project_id):
    project = Project.objects.get(id=project_id)

    if project is not None:
        if project.is_searchable or is_co_owner_or_staff(get_request_contributor(request), project):
            hydrated_project = project.hydrate_to_json()
            del hydrated_project['project_volunteers']
            return JsonResponse(hydrated_project, safe=False)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_project(request, project_id):
    project = Project.objects.get(id=project_id)
    user = get_request_contributor(request)

    if project is not None:
        if user.is_staff:
            project.is_searchable = True
            project.save()
            project.recache(recache_linked=True)
            ProjectSearchTagsCache.refresh()
            SitemapPages.update()
            notify_project_owners_project_approved(project)
            messages.success(request, 'Project Approved')
            return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_event(request, event_id):
    event = Event.objects.get(id=event_id)
    user = get_request_contributor(request)

    if event is not None:
        if user.is_staff:
            event.is_searchable = True
            event.save()
            notify_event_owners_event_approved(event)
            event.update_linked_items()
            messages.success(request, 'Event Approved')
            return redirect(section_url(FrontEndSection.AboutEvent, {'id': str(event.id)}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


@ensure_csrf_cookie
@xframe_options_exempt
@api_view()
@throttle_classes([AnonRateThrottle, UserRateThrottle])
def index(request, id='Unused but needed for routing purposes; do not remove!'):
    page = get_page_section(request.get_full_path())
    # TODO: Add to redirectors.py
    # Redirect to AddUserDetails page if First/Last name hasn't been entered yet
    if page not in [FrontEndSection.AddUserDetails.value, FrontEndSection.SignUp.value] \
            and request.user.is_authenticated and \
            (not request.user.first_name or not request.user.last_name):
        from allauth.socialaccount.models import SocialAccount
        account = SocialAccount.objects.filter(user=request.user).first()<commit_msg>Bug Fix: Update creator user context when project/group/event are approved<commit_after>import re
from django.shortcuts import redirect
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from django.core.exceptions import PermissionDenied
from django.core.paginator import Paginator
from django.conf import settings
from django.contrib import messages
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
from django.template import loader
from django.utils import timezone
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import ensure_csrf_cookie
from time import time
from urllib import parse as urlparse
import simplejson as json
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q
from .models import FileCategory, Project, ProjectFile, ProjectPosition, UserAlert, VolunteerRelation, Group, Event, \
    ProjectRelationship, Testimonial, ProjectFavorite
from .sitemaps import SitemapPages
from .caching.cache import ProjectSearchTagsCache
from common.caching.cache import Cache
from common.helpers.collections import flatten, count_occurrences
from common.helpers.db import unique_column_values
from common.helpers.s3 import presign_s3_upload, user_has_permission_for_s3_file, delete_s3_file
from common.helpers.tags import get_tags_by_category,get_tag_dictionary
from common.helpers.form_helpers import is_co_owner_or_staff, is_co_owner, is_co_owner_or_owner, is_creator_or_staff, is_creator
from .forms import ProjectCreationForm, EventCreationForm, GroupCreationForm
from common.helpers.qiqo_chat import get_user_qiqo_iframe
from democracylab.models import Contributor, get_request_contributor
from common.models.tags import Tag
from common.helpers.constants import FrontEndSection, TagCategory
from democracylab.emails import send_to_project_owners, send_to_project_volunteer, HtmlEmailTemplate, send_volunteer_application_email, \
    send_volunteer_conclude_email, notify_project_owners_volunteer_renewed_email, notify_project_owners_volunteer_concluded_email, \
    notify_project_owners_project_approved, contact_democracylab_email, send_to_group_owners, send_group_project_invitation_email, \
    notify_group_owners_group_approved, notify_event_owners_event_approved
from civictechprojects.helpers.context_preload import context_preload
from civictechprojects.helpers.projects.annotations import apply_project_annotations
from common.helpers.front_end import section_url, get_page_section, get_clean_url, redirect_from_deprecated_url
from common.helpers.redirectors import redirect_by, InvalidArgumentsRedirector, DirtyUrlsRedirector, DeprecatedUrlsRedirector
from common.helpers.user_helpers import get_my_projects, get_my_groups, get_my_events, get_user_context
from django.views.decorators.cache import cache_page
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
import requests


def get_tag_counts(category=None, event=None, group=None):
    queryset = get_tags_by_category(category) if category is not None else Tag.objects.all()
    activetagdict = ProjectSearchTagsCache.get(event=event, group=group)
    querydict = {tag.tag_name: tag for tag in queryset}
    resultdict = {}

    for slug in querydict.keys():
        resultdict[slug] = Tag.hydrate_tag_model(querydict[slug])
        resultdict[slug]['num_times'] = activetagdict[slug] if slug in activetagdict else 0
    return list(resultdict.values())


def tags(request):
    url_parts = request.GET.urlencode()
    query_terms = urlparse.parse_qs(url_parts, keep_blank_values=0, strict_parsing=0)
    category = query_terms.get('category')[0] if 'category' in query_terms else None
    queryset = get_tags_by_category(category) if category is not None else Tag.objects.all()
    tags_result = list(map(lambda tag: Tag.hydrate_tag_model(tag), queryset))
    return JsonResponse(tags_result, safe=False)


@cache_page(1200) #cache duration in seconds, cache_page docs: https://docs.djangoproject.com/en/2.1/topics/cache/#the-per-view-cache
def group_tags_counts(request):
    # Get all groups
    all_groups = Group.objects.all()
    # Get Groups issue areas
    group_issues = list(map(lambda group: group.get_project_issue_areas(with_counts=False), all_groups))
    # Count up instances of tags
    group_issues_counts = count_occurrences(flatten(group_issues))
    issue_tags = {}
    for issue_tag in group_issues_counts.keys():
        issue_tags[issue_tag] = Tag.hydrate_tag_model(Tag.get_by_name(issue_tag))
        issue_tags[issue_tag]['num_times'] = group_issues_counts[issue_tag]
    return JsonResponse(list(issue_tags.values()), safe=False)


def to_rows(items, width):
    rows = [[]]
    row_number = 0
    column_number = 0
    for item in items:
        rows[row_number].append(item)
        column_number += 1
        if column_number >= width:
            column_number = 0
            rows.append([])
            row_number += 1
    return rows


def to_tag_map(tags):
    tag_map = ((tag.tag_name, tag.display_name) for tag in tags)
    return list(tag_map)

# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def group_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    group = GroupCreationForm.create_or_edit_group(request, None)
    return JsonResponse(group.hydrate_to_json())


def group_edit(request, group_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    group = None
    try:
        group = GroupCreationForm.create_or_edit_group(request, group_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(group.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutGroup, {'id': group_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def group_delete(request, group_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        GroupCreationForm.delete_group(request, group_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_group(request, group_id):
    group = Group.objects.get(id=group_id)

    if group is not None:
        if group.is_searchable or is_creator_or_staff(get_request_contributor(request), group):
            return JsonResponse(group.hydrate_to_json())
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_group(request, group_id):
    group = Group.objects.get(id=group_id)
    user = get_request_contributor(request)

    if group is not None:
        if user.is_staff:
            group.is_searchable = True
            group.save()
            # SitemapPages.update()
            ProjectSearchTagsCache.refresh(event=None, group=group)
            notify_group_owners_group_approved(group)
            messages.success(request, 'Group Approved')
            user.purge_cache()

            return redirect(section_url(FrontEndSection.AboutGroup, {'id': str(group.id)}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def event_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    event = None
    try:
        event = EventCreationForm.create_or_edit_event(request, None)
    except PermissionDenied:
        return HttpResponseForbidden()
    return JsonResponse(event.hydrate_to_json())


def event_edit(request, event_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    event = None
    try:
        event = EventCreationForm.create_or_edit_event(request, event_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(event.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutEvent, {'id': event_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def event_delete(request, event_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        EventCreationForm.delete_event(request, event_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_event(request, event_id):
    try:
        event = Event.get_by_id_or_slug(event_id)
        if event_id.isnumeric() and event.is_private and not is_creator_or_staff(get_request_contributor(request), event):
            # Don't let non-admins/non-owners load a private event by numeric id
            raise PermissionDenied()
    except PermissionDenied:
        return HttpResponseForbidden()

    return JsonResponse(event.hydrate_to_json()) if event else HttpResponse(status=404)


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def project_create(request):
    if not request.user.is_authenticated:
        return redirect(section_url(FrontEndSection.LogIn))

    user = get_request_contributor(request)
    if not user.email_verified:
        # TODO: Log this
        return HttpResponse(status=403)

    project = ProjectCreationForm.create_or_edit_project(request, None)
    return JsonResponse(project.hydrate_to_json())


def project_edit(request, project_id):
    if not request.user.is_authenticated:
        return redirect('/signup')

    try:
        project = ProjectCreationForm.create_or_edit_project(request, project_id)
        # TODO:
        # update_cached_project_url(project_id)
    except PermissionDenied:
        return HttpResponseForbidden()

    if request.is_ajax():
        return JsonResponse(project.hydrate_to_json())
    else:
        return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))


# TODO: Pass csrf token in ajax call so we can check for it
@csrf_exempt
def project_delete(request, project_id):
    # if not logged in, send user to login page
    if not request.user.is_authenticated:
        return HttpResponse(status=401)
    try:
        ProjectCreationForm.delete_project(request, project_id)
    except PermissionDenied:
        return HttpResponseForbidden()
    return HttpResponse(status=204)


def get_project(request, project_id):
    project = Project.objects.get(id=project_id)

    if project is not None:
        if project.is_searchable or is_co_owner_or_staff(get_request_contributor(request), project):
            hydrated_project = project.hydrate_to_json()
            del hydrated_project['project_volunteers']
            return JsonResponse(hydrated_project, safe=False)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_project(request, project_id):
    project = Project.objects.get(id=project_id)
    user = get_request_contributor(request)

    if project is not None:
        if user.is_staff:
            project.is_searchable = True
            project.save()
            project.recache(recache_linked=True)
            ProjectSearchTagsCache.refresh()
            user.purge_cache()
            SitemapPages.update()
            notify_project_owners_project_approved(project)
            messages.success(request, 'Project Approved')
            return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


def approve_event(request, event_id):
    event = Event.objects.get(id=event_id)
    user = get_request_contributor(request)

    if event is not None:
        if user.is_staff:
            event.is_searchable = True
            event.save()
            notify_event_owners_event_approved(event)
            event.update_linked_items()
            user.purge_cache()
            messages.success(request, 'Event Approved')
            return redirect(section_url(FrontEndSection.AboutEvent, {'id': str(event.id)}))
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponse(status=404)


@ensure_csrf_cookie
@xframe_options_exempt
@api_view()
@throttle_classes([AnonRateThrottle, UserRateThrottle])
def index(request, id='Unused but needed for routing purposes; do not remove!'):
    page = get_page_section(request.get_full_path())
    # TODO: Add to redirectors.py
    # Redirect to AddUserDetails page if First/Last name hasn't been entered yet
    if page not in [FrontEndSection.AddUserDetails.value, FrontEndSection.SignUp.value] \
            and request.user.is_authenticated and \
            (not request.user.first_name or not request.user.last_name):
        from allauth.socialaccount.models import SocialAccount
        account = SocialAccount.objects.filter(user=request.user).first()
{'fraction_non_alphanumeric': 0.07534502051473331, 'fraction_numerical': 0.004774337933606863, 'mean_word_length': 3.9797548291233285, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, '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': '1175742', 'n_tokens_mistral': 8051, 'n_tokens_neox': 7811, 'n_words': 1851}