<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#pragma once

#include <map>

#include "js_types.hpp"
#include "schema.hpp"

namespace realm {
namespace js {

template<typename T>
struct Schema {
    using ContextType = typename T::Context;
    using FunctionType = typename T::Function;
    using ObjectType = typename T::Object;
    using ValueType = typename T::Value;
    using String = js::String<T>;
    using Object = js::Object<T>;
    using Value = js::Value<T>;

    using ObjectDefaults = std::map<std::string, Protected<ValueType>>;
    using ObjectDefaultsMap = std::map<std::string, ObjectDefaults>;
    using ConstructorMap = std::map<std::string, Protected<FunctionType>>;

    static ObjectType dict_for_property_array(ContextType, const ObjectSchema &, ObjectType);
    static Property parse_property(ContextType, ValueType, StringData, std::string, ObjectDefaults &);
    static ObjectSchema parse_object_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);
    static realm::Schema parse_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);

    static ObjectType object_for_schema(ContextType, const realm::Schema &);
    static ObjectType object_for_object_schema(ContextType, const ObjectSchema &);
    static ObjectType object_for_property(ContextType, const Property &);
};

template<typename T>
typename T::Object Schema<T>::dict_for_property_array(ContextType ctx, const ObjectSchema &object_schema, ObjectType array) {
    size_t count = object_schema.persisted_properties.size();

    if (count != Object::validated_get_length(ctx, array)) {
        throw std::runtime_error("Array must contain values for all object properties");
    }

    ObjectType dict = Object::create_empty(ctx);

    for (uint32_t i = 0; i < count; i++) {
        ValueType value = Object::get_property(ctx, array, i);
        Property prop = object_schema.persisted_properties[i];
        Object::set_property(ctx, dict, !prop.public_name.empty() ? prop.public_name : prop.name, value);
    }

    return dict;
}

static inline void parse_property_type(StringData object_name, Property& prop, StringData type)
{
    using realm::PropertyType;
    if (!type || !type.size()) {
        throw std::logic_error(util::format("Property '%1.%2' must have a non-empty type", object_name, prop.name));
    }
    if (type.ends_with("[]")) {
        prop.type |= PropertyType::Array;
        type = type.substr(0, type.size() - 2);
    }
    if (type.ends_with("?")) {
        prop.type |= PropertyType::Nullable;
        type = type.substr(0, type.size() - 1);
    }

    if (type == "bool") {
        prop.type |= PropertyType::Bool;
    }
    else if (type == "int") {
        prop.type |= PropertyType::Int;
    }
    else if (type == "float") {
        prop.type |= PropertyType::Float;
    }
    else if (type == "double") {
        prop.type |= PropertyType::Double;
    }
    else if (type == "string") {
        prop.type |= PropertyType::String;
    }
    else if (type == "date") {
        prop.type |= PropertyType::Date;
    }
    else if (type == "data") {
        prop.type |= PropertyType::Data;
    }
    else if (type == "decimal128") {
        prop.type |= PropertyType::Decimal;
    }
    else if (type == "objectId") {
        prop.type |= PropertyType::ObjectId;
    }
    else if (type == "list") {
        if (prop.object_type == "bool") {
            prop.type |= PropertyType::Bool | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "int") {
            prop.type |= PropertyType::Int | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "float") {
            prop.type |= PropertyType::Float | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "double") {
            prop.type |= PropertyType::Double | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "string") {
            prop.type |= PropertyType::String | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "date") {
            prop.type |= PropertyType::Date | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "data") {
            prop.type |= PropertyType::Data | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "decimal128") {
            prop.type |= PropertyType::Decimal | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "objectId") {
            prop.type |= PropertyType::Decimal | PropertyType::Array;
            prop.object_type = "";
        }
        else {
            if (is_nullable(prop.type)) {
                throw std::logic_error(util::format("List property '%1.%2' cannot be optional", object_name, prop.name));
            }
            if (is_array(prop.type)) {
                throw std::logic_error(util::format("List property '%1.%2' must have a non-list value type", object_name, prop.name));
            }
            prop.type |= PropertyType::Object | PropertyType::Array;
        }
    }
    else if (type == "linkingObjects") {
        prop.type |= PropertyType::LinkingObjects | PropertyType::Array;
    }
    else if (type == "object") {
        prop.type |= PropertyType::Object;
    }
    else {
        // The type could be the name of another object type in the same schema.
        prop.type |= PropertyType::Object;
        prop.object_type = type;
    }

    // Object properties are implicitly optional
    if (prop.type == PropertyType::Object && !is_array(prop.type)) {
        prop.type |= PropertyType::Nullable;
    }
}


template<typename T>
Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, StringData object_name,
                                   std::string property_name, ObjectDefaults &object_defaults) {
    static const String default_string = "default";
    static const String indexed_string = "indexed";
    static const String type_string = "type";
    static const String object_type_string = "objectType";
    static const String optional_string = "optional";
    static const String property_string = "property";
    static const String internal_name_string = "mapTo";

    Property prop;
    prop.name = std::move(property_name);

    ObjectType property_object = {};
    std::string type;

    using realm::PropertyType;

    if (Value::is_object(ctx, attributes)) {
        property_object = Value::validated_to_object(ctx, attributes);
        std::string property_type = Object::validated_get_string(ctx, property_object, type_string);
        ValueType object_type_value = Object::get_property(ctx, property_object, object_type_string);
        if (!Value::is_undefined(ctx, object_type_value)) {
            prop.object_type = Value::validated_to_string(ctx, object_type_value, "objectType");
        }
        parse_property_type(object_name, prop, property_type);

        ValueType optional_value = Object::get_property(ctx, property_object, optional_string);
        if (!Value::is_undefined(ctx, optional_value) && Value::validated_to_boolean(ctx, optional_value, "optional")) {
            prop.type |= PropertyType::Nullable;
        }

        ValueType default_value = Object::get_property(ctx, property_object, default_string);
        if (!Value::is_undefined(ctx, default_value)) {
            object_defaults.emplace(prop.name, Protected<ValueType>(ctx, default_value));
        }

        ValueType indexed_value = Object::get_property(ctx, property_object, indexed_string);
        if (!Value::is_undefined(ctx, indexed_value)) {
            prop.is_indexed = Value::validated_to_boolean(ctx, indexed_value);
        }

        ValueType internal_name_value = Object::get_property(ctx, property_object, internal_name_string);
        if (!Value::is_undefined(ctx, internal_name_value)) {
            std::string internal_name = Value::validated_to_string(ctx, internal_name_value);
            if (internal_name != prop.name) {
                prop.public_name = prop.name;
                prop.name = internal_name;
            }
        }
    }
    else {
        std::string property_type = Value::validated_to_string(ctx, attributes);
        parse_property_type(object_name, prop, property_type);
    }

    if (prop.type == PropertyType::Object && prop.object_type.empty()) {
        if (!Value::is_valid(property_object)) {
            throw std::logic_error(util::format("%1 property %2.%3 must specify 'objectType'",
                                                is_array(prop.type) ? "List" : "Object", object_name, prop.name));
        }
        prop.object_type = Object::validated_get_string(ctx, property_object, object_type_string);
    }

    if (prop.type == PropertyType::LinkingObjects) {
        if (!Value::is_valid(property_object)) {
            throw std::logic_error(util::format("Linking objects property %1.%2 must specify 'objectType'",
                                                object_name, prop.name));
        }
        prop.object_type = Object::validated_get_string(ctx, property_object, object_type_string);
        prop.link_origin_property_name = Object::validated_get_string(ctx, property_object, property_string);
    }

    return prop;
}

template<typename T>
ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType object_schema_object, ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
    static const String name_string = "name";
    static const String primary_string = "primaryKey";
    static const String properties_string = "properties";
    static const String schema_string = "schema";
    static const String embedded_string = "embedded";

    FunctionType object_constructor = {};
    if (Value::is_constructor(ctx, object_schema_object)) {
        object_constructor = Value::to_constructor(ctx, object_schema_object);
        object_schema_object = Object::validated_get_object(ctx, object_constructor, schema_string, "Realm object constructor must have a 'schema' property.");
    }

    ObjectDefaults object_defaults;
    ObjectSchema object_schema;
    object_schema.name = Object::validated_get_string(ctx, object_schema_object, name_string, "ObjectSchema");

    ObjectType properties_object = Object::validated_get_object(ctx, object_schema_object, properties_string, "ObjectSchema");
    if (Value::is_array(ctx, properties_object)) {
        uint32_t length = Object::validated_get_length(ctx, properties_object);
        for (uint32_t i = 0; i < length; i++) {
            ObjectType property_object = Object::validated_get_object(ctx, properties_object, i);
            std::string property_name = Object::validated_get_string(ctx, property_object, name_string);
            Property property;
            try {
                property = parse_property(ctx, property_object, object_schema, property_name, object_defaults);
            }
            catch (std::invalid_argument ex) {
                std::string message = util::format("Error while parsing property '%1' of object with name '%2'. Error: %3", property_name, object_schema.name, ex.what());
                throw std::logic_error(message);
            }

            if (property.type == realm::PropertyType::LinkingObjects) {
                object_schema.computed_properties.emplace_back(std::move(property));
            }
            else {
                object_schema.persisted_properties.emplace_back(std::move(property));
            }

        }
    }
    else {
        auto property_names = Object::get_property_names(ctx, properties_object);
        for (auto& property_name : property_names) {
            ValueType property_value = Object::get_property(ctx, properties_object, property_name);
            Property property;
            try {
                property = parse_property(ctx, property_value, object_schema, property_name, object_defaults);
            }
            catch (std::invalid_argument ex) {
                std::string message = util::format("Error while parsing property '%1' of object with name '%2'. Error: %3", property_name, object_schema.name, ex.what());
                throw std::logic_error(message);
            }
            if (property.type == realm::PropertyType::LinkingObjects) {
                object_schema.computed_properties.emplace_back(std::move(property));
            }
            else {
                object_schema.persisted_properties.emplace_back(std::move(property));
            }
        }
    }

    ValueType primary_value = Object::get_property(ctx, object_schema_object, primary_string);
    if (!Value::is_undefined(ctx, primary_value)) {
        object_schema.primary_key = Value::validated_to_string(ctx, primary_value);
        Property *property = object_schema.primary_key_property();
        if (!property) {
            throw std::runtime_error("Schema named '" + object_schema.name + "' specifies primary key of '" + object_schema.primary_key + "' but does not declare a property of that name.");
        }
        property->is_primary = true;
    }

    ValueType embedded_value = Object::get_property(ctx, object_schema_object, embedded_string);<commit_msg>fix argument<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#pragma once

#include <map>

#include "js_types.hpp"
#include "schema.hpp"

namespace realm {
namespace js {

template<typename T>
struct Schema {
    using ContextType = typename T::Context;
    using FunctionType = typename T::Function;
    using ObjectType = typename T::Object;
    using ValueType = typename T::Value;
    using String = js::String<T>;
    using Object = js::Object<T>;
    using Value = js::Value<T>;

    using ObjectDefaults = std::map<std::string, Protected<ValueType>>;
    using ObjectDefaultsMap = std::map<std::string, ObjectDefaults>;
    using ConstructorMap = std::map<std::string, Protected<FunctionType>>;

    static ObjectType dict_for_property_array(ContextType, const ObjectSchema &, ObjectType);
    static Property parse_property(ContextType, ValueType, StringData, std::string, ObjectDefaults &);
    static ObjectSchema parse_object_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);
    static realm::Schema parse_schema(ContextType, ObjectType, ObjectDefaultsMap &, ConstructorMap &);

    static ObjectType object_for_schema(ContextType, const realm::Schema &);
    static ObjectType object_for_object_schema(ContextType, const ObjectSchema &);
    static ObjectType object_for_property(ContextType, const Property &);
};

template<typename T>
typename T::Object Schema<T>::dict_for_property_array(ContextType ctx, const ObjectSchema &object_schema, ObjectType array) {
    size_t count = object_schema.persisted_properties.size();

    if (count != Object::validated_get_length(ctx, array)) {
        throw std::runtime_error("Array must contain values for all object properties");
    }

    ObjectType dict = Object::create_empty(ctx);

    for (uint32_t i = 0; i < count; i++) {
        ValueType value = Object::get_property(ctx, array, i);
        Property prop = object_schema.persisted_properties[i];
        Object::set_property(ctx, dict, !prop.public_name.empty() ? prop.public_name : prop.name, value);
    }

    return dict;
}

static inline void parse_property_type(StringData object_name, Property& prop, StringData type)
{
    using realm::PropertyType;
    if (!type || !type.size()) {
        throw std::logic_error(util::format("Property '%1.%2' must have a non-empty type", object_name, prop.name));
    }
    if (type.ends_with("[]")) {
        prop.type |= PropertyType::Array;
        type = type.substr(0, type.size() - 2);
    }
    if (type.ends_with("?")) {
        prop.type |= PropertyType::Nullable;
        type = type.substr(0, type.size() - 1);
    }

    if (type == "bool") {
        prop.type |= PropertyType::Bool;
    }
    else if (type == "int") {
        prop.type |= PropertyType::Int;
    }
    else if (type == "float") {
        prop.type |= PropertyType::Float;
    }
    else if (type == "double") {
        prop.type |= PropertyType::Double;
    }
    else if (type == "string") {
        prop.type |= PropertyType::String;
    }
    else if (type == "date") {
        prop.type |= PropertyType::Date;
    }
    else if (type == "data") {
        prop.type |= PropertyType::Data;
    }
    else if (type == "decimal128") {
        prop.type |= PropertyType::Decimal;
    }
    else if (type == "objectId") {
        prop.type |= PropertyType::ObjectId;
    }
    else if (type == "list") {
        if (prop.object_type == "bool") {
            prop.type |= PropertyType::Bool | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "int") {
            prop.type |= PropertyType::Int | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "float") {
            prop.type |= PropertyType::Float | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "double") {
            prop.type |= PropertyType::Double | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "string") {
            prop.type |= PropertyType::String | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "date") {
            prop.type |= PropertyType::Date | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "data") {
            prop.type |= PropertyType::Data | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "decimal128") {
            prop.type |= PropertyType::Decimal | PropertyType::Array;
            prop.object_type = "";
        }
        else if (prop.object_type == "objectId") {
            prop.type |= PropertyType::Decimal | PropertyType::Array;
            prop.object_type = "";
        }
        else {
            if (is_nullable(prop.type)) {
                throw std::logic_error(util::format("List property '%1.%2' cannot be optional", object_name, prop.name));
            }
            if (is_array(prop.type)) {
                throw std::logic_error(util::format("List property '%1.%2' must have a non-list value type", object_name, prop.name));
            }
            prop.type |= PropertyType::Object | PropertyType::Array;
        }
    }
    else if (type == "linkingObjects") {
        prop.type |= PropertyType::LinkingObjects | PropertyType::Array;
    }
    else if (type == "object") {
        prop.type |= PropertyType::Object;
    }
    else {
        // The type could be the name of another object type in the same schema.
        prop.type |= PropertyType::Object;
        prop.object_type = type;
    }

    // Object properties are implicitly optional
    if (prop.type == PropertyType::Object && !is_array(prop.type)) {
        prop.type |= PropertyType::Nullable;
    }
}


template<typename T>
Property Schema<T>::parse_property(ContextType ctx, ValueType attributes, StringData object_name,
                                   std::string property_name, ObjectDefaults &object_defaults) {
    static const String default_string = "default";
    static const String indexed_string = "indexed";
    static const String type_string = "type";
    static const String object_type_string = "objectType";
    static const String optional_string = "optional";
    static const String property_string = "property";
    static const String internal_name_string = "mapTo";

    Property prop;
    prop.name = std::move(property_name);

    ObjectType property_object = {};
    std::string type;

    using realm::PropertyType;

    if (Value::is_object(ctx, attributes)) {
        property_object = Value::validated_to_object(ctx, attributes);
        std::string property_type = Object::validated_get_string(ctx, property_object, type_string);
        ValueType object_type_value = Object::get_property(ctx, property_object, object_type_string);
        if (!Value::is_undefined(ctx, object_type_value)) {
            prop.object_type = Value::validated_to_string(ctx, object_type_value, "objectType");
        }
        parse_property_type(object_name, prop, property_type);

        ValueType optional_value = Object::get_property(ctx, property_object, optional_string);
        if (!Value::is_undefined(ctx, optional_value) && Value::validated_to_boolean(ctx, optional_value, "optional")) {
            prop.type |= PropertyType::Nullable;
        }

        ValueType default_value = Object::get_property(ctx, property_object, default_string);
        if (!Value::is_undefined(ctx, default_value)) {
            object_defaults.emplace(prop.name, Protected<ValueType>(ctx, default_value));
        }

        ValueType indexed_value = Object::get_property(ctx, property_object, indexed_string);
        if (!Value::is_undefined(ctx, indexed_value)) {
            prop.is_indexed = Value::validated_to_boolean(ctx, indexed_value);
        }

        ValueType internal_name_value = Object::get_property(ctx, property_object, internal_name_string);
        if (!Value::is_undefined(ctx, internal_name_value)) {
            std::string internal_name = Value::validated_to_string(ctx, internal_name_value);
            if (internal_name != prop.name) {
                prop.public_name = prop.name;
                prop.name = internal_name;
            }
        }
    }
    else {
        std::string property_type = Value::validated_to_string(ctx, attributes);
        parse_property_type(object_name, prop, property_type);
    }

    if (prop.type == PropertyType::Object && prop.object_type.empty()) {
        if (!Value::is_valid(property_object)) {
            throw std::logic_error(util::format("%1 property %2.%3 must specify 'objectType'",
                                                is_array(prop.type) ? "List" : "Object", object_name, prop.name));
        }
        prop.object_type = Object::validated_get_string(ctx, property_object, object_type_string);
    }

    if (prop.type == PropertyType::LinkingObjects) {
        if (!Value::is_valid(property_object)) {
            throw std::logic_error(util::format("Linking objects property %1.%2 must specify 'objectType'",
                                                object_name, prop.name));
        }
        prop.object_type = Object::validated_get_string(ctx, property_object, object_type_string);
        prop.link_origin_property_name = Object::validated_get_string(ctx, property_object, property_string);
    }

    return prop;
}

template<typename T>
ObjectSchema Schema<T>::parse_object_schema(ContextType ctx, ObjectType object_schema_object, ObjectDefaultsMap &defaults, ConstructorMap &constructors) {
    static const String name_string = "name";
    static const String primary_string = "primaryKey";
    static const String properties_string = "properties";
    static const String schema_string = "schema";
    static const String embedded_string = "embedded";

    FunctionType object_constructor = {};
    if (Value::is_constructor(ctx, object_schema_object)) {
        object_constructor = Value::to_constructor(ctx, object_schema_object);
        object_schema_object = Object::validated_get_object(ctx, object_constructor, schema_string, "Realm object constructor must have a 'schema' property.");
    }

    ObjectDefaults object_defaults;
    ObjectSchema object_schema;
    object_schema.name = Object::validated_get_string(ctx, object_schema_object, name_string, "ObjectSchema");

    ObjectType properties_object = Object::validated_get_object(ctx, object_schema_object, properties_string, "ObjectSchema");
    if (Value::is_array(ctx, properties_object)) {
        uint32_t length = Object::validated_get_length(ctx, properties_object);
        for (uint32_t i = 0; i < length; i++) {
            ObjectType property_object = Object::validated_get_object(ctx, properties_object, i);
            std::string property_name = Object::validated_get_string(ctx, property_object, name_string);
            Property property;
            try {
                property = parse_property(ctx, property_object, object_schema.name, property_name, object_defaults);
            }
            catch (std::invalid_argument ex) {
                std::string message = util::format("Error while parsing property '%1' of object with name '%2'. Error: %3", property_name, object_schema.name, ex.what());
                throw std::logic_error(message);
            }

            if (property.type == realm::PropertyType::LinkingObjects) {
                object_schema.computed_properties.emplace_back(std::move(property));
            }
            else {
                object_schema.persisted_properties.emplace_back(std::move(property));
            }

        }
    }
    else {
        auto property_names = Object::get_property_names(ctx, properties_object);
        for (auto& property_name : property_names) {
            ValueType property_value = Object::get_property(ctx, properties_object, property_name);
            Property property;
            try {
                property = parse_property(ctx, property_value, object_schema.name, property_name, object_defaults);
            }
            catch (std::invalid_argument ex) {
                std::string message = util::format("Error while parsing property '%1' of object with name '%2'. Error: %3", property_name, object_schema.name, ex.what());
                throw std::logic_error(message);
            }
            if (property.type == realm::PropertyType::LinkingObjects) {
                object_schema.computed_properties.emplace_back(std::move(property));
            }
            else {
                object_schema.persisted_properties.emplace_back(std::move(property));
            }
        }
    }

    ValueType primary_value = Object::get_property(ctx, object_schema_object, primary_string);
    if (!Value::is_undefined(ctx, primary_value)) {
        object_schema.primary_key = Value::validated_to_string(ctx, primary_value);
        Property *property = object_schema.primary_key_property();
        if (!property) {
            throw std::runtime_error("Schema named '" + object_schema.name + "' specifies primary key of '" + object_schema.primary_key + "' but does not declare a property of that name.");
        }
        property->is_primary = true;
    }

    ValueType embedded_value = Object::get_property(ctx, object_schema_object, embedded_string);
{'fraction_non_alphanumeric': 0.12606026191574687, 'fraction_numerical': 0.0030521347198069347, 'mean_word_length': 2.858942755409477, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7104246', 'n_tokens_mistral': 7754, 'n_tokens_neox': 7569, 'n_words': 1774}