diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..250f496 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,37 @@ +FROM rust:1.90.0 + +# Install basic development tools +RUN apt-get update && apt-get install -y \ + build-essential \ + gdb \ + git \ + procps \ + sudo \ + && rm -rf /var/lib/apt/lists/* + +# Create developer user with host UID/GID +ARG USER_UID=1000 +ARG USER_GID=1000 +ENV USER_UID=${USER_UID:-1000} +ENV USER_GID=${USER_GID:-1000} +RUN groupadd -g $USER_GID developer \ + && useradd -u $USER_UID -g $USER_GID -m developer \ + && mkdir -p /workspace \ + && chown developer:developer /workspace + +RUN echo 'developer ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/developer \ + && chmod 0440 /etc/sudoers.d/developer + +RUN mkdir -p /home/developer/.vscode-server \ + && chown -R developer:developer /home/developer/.vscode-server + +# Switch to developer user +USER developer + +RUN rustup component add rustfmt + +# Set up cargo path +ENV PATH="/home/developer/.cargo/bin:${PATH}" + +# Set default workspace directory +WORKDIR /workspace \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..1027a78 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,45 @@ +{ + "name": "Rust Development", + "build": { + "dockerfile": "Dockerfile", + "args": { + "USER_UID": "${localEnv:UID:1000}", + "USER_GID": "${localEnv:GID:1000}" + } + }, + "remoteUser": "developer", + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "fill-labs.dependi", + "jalalalizz.cargo-toolset", + "tamasfe.even-better-toml", + "vadimcn.vscode-lldb", + "frosticless.monokai-one-darker", + "ms-vscode.cpptools" + ], + "settings": { + "workbench.colorTheme": "Monokai One Darker", + "terminal.integrated.defaultProfile.linux": "bash", + "rust-analyzer.checkOnSave": true, + "rust-analyzer.cargo.loadOutDirsFromCheck": true, + "rust-analyzer.procMacro.enable": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true + } + } + } + }, + "forwardPorts": [8080, 3000], + "runArgs": [ + "--name", + "${localEnv:USER}-${localWorkspaceFolderBasename}-rust-dev", + "--mount", + "type=volume,source=vscode-extensions,target=/home/developer/.vscode-server/extensions" + ], + "postStartCommand": "sudo chown -R $(id -u):$(id -g) ~/.vscode-server || true", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", + "workspaceFolder": "/workspace" +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e3217b7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = [ + "app", + "lib", +] +resolver = "3" + +[workspace.package] +edition = "2024" +authors = ["chodak166 "] + +[profile.release] +lto = true # Link Time Optimization: Analyzes entire program for optimizations +codegen-units = 1 # Forces single-threaded compilation (slower build, but smaller/faster binary) diff --git a/app/Cargo.toml b/app/Cargo.toml new file mode 100644 index 0000000..7f87eb2 --- /dev/null +++ b/app/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "phomnemic" +version = "0.1.0" +edition = "2024" + +[dependencies] +# Internal +applib = { path = "../lib" } + + +# Runtime & Async +tokio = { version = "1.48", features = ["full"] } +anyhow = "1.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +async-trait = "0.1" + +# Configuration & Inputs +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +toml = "0.9.8" +clap = { version = "4.5", features = ["derive", "env"] } +config = "0.15.19" +const_format = "0.2.35" diff --git a/app/src/app.rs b/app/src/app.rs new file mode 100644 index 0000000..a5accbf --- /dev/null +++ b/app/src/app.rs @@ -0,0 +1,42 @@ +use crate::commands::{AppCommand, CliArgs}; +use crate::config::AppConfig; +use crate::container::Container; +use anyhow::Result; +use clap::Parser; +use tracing::debug; + +pub struct Application { + config: AppConfig, + container: Container, + command: Box, +} + +impl Application { + pub async fn build() -> Result { + let args = CliArgs::parse(); + + let app_cmd = args.command.into_app_command(); + + let config = AppConfig::build(&args.global, app_cmd.as_ref())?; + + tracing_subscriber::fmt() + .compact() + .with_env_filter(&config.log_level) + .with_target(false) + .init(); + + debug!("Bootstrapping application..."); + + let container = Container::new().await?; + + Ok(Self { + config, + container, + command: app_cmd, + }) + } + + pub async fn run(self) -> Result<()> { + self.command.execute(&self.config, &self.container).await + } +} diff --git a/app/src/commands.rs b/app/src/commands.rs new file mode 100644 index 0000000..ab7645a --- /dev/null +++ b/app/src/commands.rs @@ -0,0 +1,84 @@ +pub mod decode; +pub mod encode; +pub mod import_dict; + +use crate::config::AppConfig; +use crate::container::Container; +use anyhow::Result; +use async_trait::async_trait; +use clap::Subcommand; +use clap::{Args as ClapArgs, Parser}; +use config::ConfigBuilder; +use config::builder::DefaultState; +use std::path::PathBuf; + +#[derive(Subcommand, Debug, Clone)] +pub enum Command { + /// Decode a word using given system + Decode(decode::DecodeCmd), + + /// Encode a number using given system + Encode(encode::EncodeCmd), + + /// Import dictionary + ImportDict(import_dict::ImportDictCmd), +} + +impl Command { + pub fn into_app_command(self) -> Box { + match self { + Command::Decode(cmd) => Box::new(cmd), + Command::Encode(cmd) => Box::new(cmd), + Command::ImportDict(cmd) => Box::new(cmd), + } + } +} + +#[derive(Parser, Debug)] +#[command(author, version, about)] +pub struct CliArgs { + #[command(flatten)] + pub global: GlobalArgs, + + #[command(subcommand)] + pub command: Command, +} + +#[derive(ClapArgs, Debug)] +pub struct GlobalArgs { + /// Path to config file + #[arg(short, long, default_value = "config.toml")] + pub config: PathBuf, + + #[arg(long, help = defaults::HELP_LOG)] + pub log_level: Option, +} + +pub trait Configurable { + fn apply_defaults( + &self, + builder: ConfigBuilder, + ) -> Result>; + fn apply_overrides( + &self, + builder: ConfigBuilder, + ) -> Result>; +} + +#[async_trait] +pub trait Executable { + async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()>; +} + +// AppCommand must be dyn-compatible. Configurable is already dyn-compatible. +// Executable is dyn-compatible because of #[async_trait]. +pub trait AppCommand: Configurable + Executable {} + +impl AppCommand for T {} + +mod defaults { + use const_format::formatcp; + + pub const LOG_LEVEL: &str = "info"; + pub const HELP_LOG: &str = formatcp!("Override Log Level [default: {}]", LOG_LEVEL); +} diff --git a/app/src/commands/decode.rs b/app/src/commands/decode.rs new file mode 100644 index 0000000..95c53f1 --- /dev/null +++ b/app/src/commands/decode.rs @@ -0,0 +1,77 @@ +use crate::commands::{ClapArgs, Configurable, Executable}; +use crate::config::AppConfig; +use crate::config::System; +use crate::container::Container; + +use anyhow::{Context, Result}; +use async_trait::async_trait; +use config::ConfigBuilder; +use config::builder::DefaultState; +use serde::Deserialize; + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub system: System, + pub input: String, +} + +#[derive(ClapArgs, Debug, Clone)] +pub struct DecodeCmd { + #[arg(short, long, help = defaults::HELP_DEC_SYSTEM)] + pub system: Option, + + #[arg(short, long, help = defaults::HELP_DEC_INPUT)] + pub input: String, +} + +impl Configurable for DecodeCmd { + fn apply_defaults( + &self, + builder: ConfigBuilder, + ) -> Result> { + builder + .set_default("decode.system", defaults::DEC_SYSTEM_NAME)? + .set_default("decode.input", "") + .map_err(Into::into) + } + + fn apply_overrides( + &self, + builder: ConfigBuilder, + ) -> Result> { + let mut builder = builder; + if let Some(ref system) = self.system { + builder = builder.set_override("decode.system", system.clone())?; + } + builder = builder.set_override("decode.input", self.input.clone())?; + + Ok(builder) + } +} + +#[async_trait] +impl Executable for DecodeCmd { + async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { + let config = config + .decode + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Decoder config missing"))?; + + let decoder = container.create_decoder(&config)?; + + let result = decoder + .decode(&config.input) + .with_context(|| format!("Failed to decode input: {}", config.input))?; + + let json = serde_json::to_string_pretty(&result).expect("JSON serialization failed"); + println!("{}", json); + Ok(()) + } +} + +mod defaults { + use const_format::formatcp; + pub const DEC_SYSTEM_NAME: &str = "major_pl"; + pub const HELP_DEC_SYSTEM: &str = formatcp!("System to use [default: {}]", DEC_SYSTEM_NAME); + pub const HELP_DEC_INPUT: &str = formatcp!("Text to decode"); +} diff --git a/app/src/commands/encode.rs b/app/src/commands/encode.rs new file mode 100644 index 0000000..c4e288a --- /dev/null +++ b/app/src/commands/encode.rs @@ -0,0 +1,90 @@ +use serde::Deserialize; + +use crate::commands::{ClapArgs, Configurable, Executable}; +use crate::config::{AppConfig, System}; +use crate::container::Container; + +use anyhow::Result; +use async_trait::async_trait; +use config::ConfigBuilder; +use config::builder::DefaultState; + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub system: System, + pub input: String, + pub dict_name: String, +} + +#[derive(ClapArgs, Debug, Clone)] +pub struct EncodeCmd { + #[arg(short, long, help = defaults::HELP_ENC_SYSTEM)] + pub system: Option, + + #[arg(short, long, help = defaults::HELP_ENC_DICT)] + pub dict_name: Option, + + #[arg(short, long, help = defaults::HELP_ENC_INPUT)] + pub input: String, +} + +impl Configurable for EncodeCmd { + fn apply_defaults( + &self, + builder: ConfigBuilder, + ) -> Result> { + builder + .set_default("encode.system", defaults::ENC_SYSTEM_NAME)? + .set_default("encode.dict_name", defaults::ENC_DICT_NAME)? + .set_default("encode.input", "") + .map_err(Into::into) + } + + fn apply_overrides( + &self, + builder: ConfigBuilder, + ) -> Result> { + let mut builder = builder; + + if let Some(system) = &self.system { + builder = builder.set_override("encode.system", system.clone())?; + } + if let Some(dict_name) = &self.dict_name { + builder = builder.set_override("encode.dict_name", dict_name.clone())?; + } + builder = builder.set_override("encode.input", self.input.clone())?; + Ok(builder) + } +} + +#[async_trait] +impl Executable for EncodeCmd { + async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { + let config = config + .encode + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Encoder config not set"))?; + + let encoder = container.create_encoder(&config).await?; + let result = encoder.encode(&config.input); + + match result { + Ok(res) => { + let json = serde_json::to_string_pretty(&res).expect("JSON serialization failed"); + println!("{}", json); + } + Err(e) => eprintln!("Error encoding: {:?}", e), + } + + Ok(()) + } +} + +mod defaults { + use const_format::formatcp; + pub const ENC_SYSTEM_NAME: &str = "major_pl"; + pub const ENC_DICT_NAME: &str = "demo_pl"; + pub const HELP_ENC_SYSTEM: &str = formatcp!("System to use [default: {}]", ENC_SYSTEM_NAME); + pub const HELP_ENC_INPUT: &str = formatcp!("Number to encode"); + pub const HELP_ENC_DICT: &str = formatcp!("Dictionary to use [default: {}]", ENC_DICT_NAME); +} diff --git a/app/src/commands/import_dict.rs b/app/src/commands/import_dict.rs new file mode 100644 index 0000000..b989f8e --- /dev/null +++ b/app/src/commands/import_dict.rs @@ -0,0 +1,71 @@ +use crate::commands::{ClapArgs, Configurable, Executable}; +use crate::config::AppConfig; +use crate::container::Container; +use anyhow::Result; +use async_trait::async_trait; +use config::ConfigBuilder; +use config::builder::DefaultState; +use serde::Deserialize; + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub name: String, + pub path: String, +} + +#[derive(ClapArgs, Debug, Clone)] +pub struct ImportDictCmd { + #[arg(long, help = defaults::HELP_IMPORT_DICT_NAME)] + pub name: String, + + #[arg(long, help = defaults::HELP_IMPORT_DICT_INPUT)] + pub path: String, +} + +impl Configurable for ImportDictCmd { + fn apply_defaults( + &self, + builder: ConfigBuilder, + ) -> Result> { + builder + .set_default("import_dict.name", defaults::IMPORT_DICT_NAME)? + .set_default("import_dict.path", defaults::IMPORT_DICT_PATH) + .map_err(Into::into) + } + + fn apply_overrides( + &self, + builder: ConfigBuilder, + ) -> Result> { + builder + .set_override("import_dict.name", self.name.clone())? + .set_override("import_dict.path", self.path.clone()) + .map_err(Into::into) + } +} + +#[async_trait] +impl Executable for ImportDictCmd { + async fn execute(&self, config: &AppConfig, container: &Container) -> Result<()> { + let config = config + .import_dict + .as_ref() + .expect("ImportDict config not set"); + let importer = container.create_dict_importer(&config.name).await?; + + // Importer expects an impl DictSource + // We need to create a DictSource from the path + use applib::JsonFileDictSource; + let source = JsonFileDictSource::new(&config.path)?; + importer.import(source).await?; + Ok(()) + } +} + +mod defaults { + use const_format::formatcp; + pub const IMPORT_DICT_NAME: &str = ""; + pub const IMPORT_DICT_PATH: &str = ""; + pub const HELP_IMPORT_DICT_NAME: &str = formatcp!("Dictionary name"); + pub const HELP_IMPORT_DICT_INPUT: &str = formatcp!("Dictionary file path"); +} diff --git a/app/src/config.rs b/app/src/config.rs new file mode 100644 index 0000000..23acf15 --- /dev/null +++ b/app/src/config.rs @@ -0,0 +1,69 @@ +use crate::commands::*; +// use crate::commands::{Configurable, GlobalArgs}; +use anyhow::{Context, Result}; +use config::{Config, Environment, File}; +use serde::Deserialize; + +#[derive(Debug, Deserialize, Clone)] +pub struct AppConfig { + #[serde(default)] + pub decode: Option, + #[serde(default)] + pub encode: Option, + #[serde(default)] + pub import_dict: Option, + pub log_level: String, +} + +impl AppConfig { + pub fn build(args: &GlobalArgs, handler: &dyn Configurable) -> Result { + let mut builder = Config::builder(); + + // Command-specific defaults via Trait + builder = handler.apply_defaults(builder)?; + + // File Layer + let config_path = &args.config; + let is_default_path = config_path.to_str() == Some("config.toml"); + + builder = builder.add_source(File::from(config_path.as_path()).required(!is_default_path)); + + // Environment Layer (e.g. APP_LISTEN_PORT) + builder = builder.add_source(Environment::with_prefix("APP").separator("_")); + + // Global log level override + if let Some(ref level) = args.log_level { + builder = builder.set_override("log_level", level.clone())?; + } + + // Command-specific overrides via Trait + builder = handler.apply_overrides(builder)?; + + builder + .build() + .context("Failed to build configuration layers")? + .try_deserialize() + .context("Failed to deserialize Config") + } +} + +// TODO: move? + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +pub enum System { + #[serde(rename = "major_en")] + MajorEn, + #[serde(rename = "major_pl")] + MajorPl, +} + +// from: +impl From<&str> for System { + fn from(s: &str) -> Self { + match s { + "major_en" => System::MajorEn, + "major_pl" => System::MajorPl, + _ => panic!("Unknown system: {}", s), + } + } +} diff --git a/app/src/container.rs b/app/src/container.rs new file mode 100644 index 0000000..0a82a73 --- /dev/null +++ b/app/src/container.rs @@ -0,0 +1,68 @@ +use std::sync::Arc; + +// use crate::config::AppConfig; +use applib::DictImporter; +use applib::DictRepository; +use applib::SqliteDictRepository; +use applib::SystemDecoder; +use applib::SystemEncoder; +use applib::sys_major as major; + +use crate::commands::decode; +use crate::commands::encode; +use crate::config::System; + +#[derive(Clone)] +pub struct Container; + +impl Container { + pub async fn new() -> anyhow::Result { + Ok(Self) + } + + pub async fn create_dict_importer(&self, dict_name: &str) -> anyhow::Result { + let repo = self.create_dict_repo(dict_name).await?; + Ok(DictImporter::new(repo)) + } + + pub async fn create_dict_repo( + &self, + dict_name: &str, + ) -> anyhow::Result> { + let mut dict_repo = SqliteDictRepository::new("sqlite:app.db").await?; + dict_repo.use_dict(dict_name); + Ok(Arc::new(dict_repo)) + } + + pub fn create_decoder( + &self, + config: &decode::Config, + ) -> anyhow::Result> { + Ok(match config.system { + System::MajorPl => Box::new(major::Decoder::new(major::rules_pl::get_rules())), + System::MajorEn => Box::new(major::Decoder::new(major::rules_en::get_rules())), + }) + } + + pub async fn create_encoder( + &self, + config: &encode::Config, + ) -> anyhow::Result> { + let dict = self.create_dict_repo(&config.dict_name).await?; + + let dec_config = decode::Config { + system: config.system.clone(), + input: String::new(), + }; + let decoder = self.create_decoder(&dec_config)?; + + let words_stream = dict.stream_batches(1000).await.unwrap(); + + let lvmap = major::LenValueMap::from_stream(words_stream, &(*decoder)) + .await + .unwrap(); + + let encoder = major::Encoder::new(lvmap); + Ok(Box::new(encoder)) + } +} diff --git a/app/src/main.rs b/app/src/main.rs new file mode 100644 index 0000000..377c91b --- /dev/null +++ b/app/src/main.rs @@ -0,0 +1,14 @@ +mod app; +mod commands; +mod config; +mod container; + +use anyhow::Result; +use app::Application; + +#[tokio::main] +async fn main() -> Result<()> { + let app = Application::build().await?; + app.run().await?; + Ok(()) +} diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..db1cf0c --- /dev/null +++ b/config.toml @@ -0,0 +1,4 @@ +log_level = "info" + +[decode] +input = "CONFIGTEST" diff --git a/lib/Cargo.toml b/lib/Cargo.toml new file mode 100644 index 0000000..a62f2e5 --- /dev/null +++ b/lib/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "applib" +version = "0.1.0" +edition = "2024" + +[dependencies] +once_cell = "1.21.3" +# clap = { version = "4.5", features = ["derive", "env"] } # Removed +const_format = "0.2.35" +config = "0.15.19" +tracing = "0.1" +tokio = { version = "1.48", features = ["full"] } +anyhow = "1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +chrono = { version = "0.4", features = ["serde"] } +thiserror = "2.0" +async-trait = "0.1" +parking_lot = "0.12" +sqlx = { version = "0.8.6", features = ["runtime-tokio", "sqlite", "chrono", "migrate"] } +futures = "0.3.31" + +[dev-dependencies] +mockall = "0.14.0" diff --git a/lib/src/common.rs b/lib/src/common.rs new file mode 100644 index 0000000..b7854fc --- /dev/null +++ b/lib/src/common.rs @@ -0,0 +1,7 @@ +pub mod entities; +pub mod errors; +pub mod traits; + +pub use self::traits::DictRepository; +pub use self::traits::SystemDecoder; +pub use self::traits::SystemEncoder; diff --git a/lib/src/common/entities.rs b/lib/src/common/entities.rs new file mode 100644 index 0000000..ffb209b --- /dev/null +++ b/lib/src/common/entities.rs @@ -0,0 +1,146 @@ +use super::errors::CodecError; +use serde::Serialize; +use std::num::ParseIntError; +use std::ops::Deref; +use std::{collections::HashMap, u64}; + +/// A number encoded as a sequence of words +#[derive(Debug, Clone, Serialize)] +pub struct EncodedPart { + pub value: u64, + pub words: Vec, +} + +/// A way (variant) to split input number +pub type EncodedSplit = Vec; + +/// A number encoded as words, split in multiple ways +#[derive(Debug, Clone, Serialize)] +pub struct EncodedValue(Vec); + +impl EncodedValue { + pub fn new(data: Vec) -> Self { + EncodedValue(data) + } +} + +impl Deref for EncodedValue { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// The number value can be encoded as many word sets, +/// but decoded as one number. For partial values +/// and dictionary words (reasonable length), we can use +/// u64 (20-digit number), but the whole input text can +/// be longer than 20 digits, so we operate on String (<= 255). +#[derive(Debug, Serialize, Clone, PartialEq, Eq)] +pub struct DecodedValue(String); + +impl DecodedValue { + pub fn new(value: String) -> Result { + if value.len() > u8::MAX as usize { + Err(CodecError::TextTooLong(value.len())) + } else { + Ok(Self(value)) + } + } + + pub fn as_str(&self) -> &str { + &self.0 + } + + pub fn parse(&self) -> Result { + self.0.parse() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn value_len(&self) -> Result { + if self.len() == 0 { + return Err(CodecError::EmptyValue); + } + DecodedLength::try_from(self.len()) + } +} + +impl PartialEq<&str> for DecodedValue { + fn eq(&self, other: &&str) -> bool { + &self.0 == *other + } +} + +impl PartialEq for &str { + fn eq(&self, other: &DecodedValue) -> bool { + *self == &other.0 + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct DecodedLength(u8); + +impl DecodedLength { + pub const fn from(value: u8) -> Self { + Self(value) + } +} + +impl TryFrom for DecodedLength { + type Error = CodecError; + fn try_from(value: usize) -> Result { + if value > u8::MAX as usize { + Err(CodecError::ValueLimitExceeded(value)) + } else { + Ok(Self(value as u8)) + } + } +} + +// --- Dictionary --- + +pub type DictEntryId = u64; + +#[derive(Debug, Clone, PartialEq)] +pub struct DictEntry { + pub id: Option, + pub text: String, + pub metadata: HashMap, +} + +impl DictEntry { + pub fn new(id: Option, text: String) -> Self { + DictEntry { + id, + text, + metadata: HashMap::new(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Dict { + pub name: String, + pub entries: HashMap, +} + +impl Dict { + pub fn new(name: String) -> Self { + Dict { + name, + entries: HashMap::new(), + } + } + + pub fn add_entry(&mut self, entry: DictEntry) { + self.entries.insert(entry.id.unwrap(), entry); + } +} diff --git a/lib/src/common/errors.rs b/lib/src/common/errors.rs new file mode 100644 index 0000000..7f05a37 --- /dev/null +++ b/lib/src/common/errors.rs @@ -0,0 +1,31 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum RepositoryError { + #[error("Data source connection failed")] + ConnectionFailed, + + #[error("'{0}' not found")] + NotFound(String), + + #[error("Storage error: {0}")] + StorageError(String), +} + +#[derive(Debug, Error)] +pub enum CodecError { + #[error("text too long: {0} bytes")] + TextTooLong(usize), + + #[error("value too large: {0}/255")] + ValueLimitExceeded(usize), + + #[error("operation not allowed on empty value")] + EmptyValue, + + #[error("initialization failed")] + InitializationFailed, + + #[error("unexpected error: {0}")] + UnexpectedError(String), +} diff --git a/lib/src/common/traits.rs b/lib/src/common/traits.rs new file mode 100644 index 0000000..5322dee --- /dev/null +++ b/lib/src/common/traits.rs @@ -0,0 +1,41 @@ +use futures::stream::BoxStream; + +use crate::common::{ + entities::{DecodedValue, Dict, DictEntry, EncodedValue}, + errors::{CodecError, RepositoryError}, +}; + +pub trait SystemDecoder: Send + Sync { + fn decode(&self, word: &str) -> Result; +} + +pub trait SystemEncoder: Send + Sync { + fn initialize(&self) -> Result<(), CodecError>; + fn encode(&self, word: &str) -> Result; +} + +#[async_trait::async_trait] +pub trait DictRepository: Send + Sync { + fn use_dict(&mut self, name: &str); + async fn create_dict(&self) -> Result<(), RepositoryError>; + + /// "Upsert" logic: + /// - If entry exists (by text), update metadata. + /// - If not, insert new. + /// - IDs are handled by the Database. + async fn save_entries(&self, entries: &[DictEntry]) -> Result<(), RepositoryError>; + + /// Fetch a page of entries. + async fn fetch_many(&self, limit: usize, offset: usize) -> Result; + + /// Returns a cold stream that fetches strings in chunks. + /// The stream yields `Result, RepositoryError>`. + async fn stream_batches( + &self, + batch_size: usize, + ) -> Result, RepositoryError>>, RepositoryError>; +} + +pub trait DictSource { + fn next_entry(&mut self) -> Option>; +} diff --git a/lib/src/dictionary.rs b/lib/src/dictionary.rs new file mode 100644 index 0000000..fedb896 --- /dev/null +++ b/lib/src/dictionary.rs @@ -0,0 +1,6 @@ +mod dict_importer; +mod infrastructure; + +pub use self::dict_importer::DictImporter; +pub use self::infrastructure::json_file_dict_source::JsonFileDictSource; +pub use self::infrastructure::sqlite_dict_repository::SqliteDictRepository; diff --git a/lib/src/dictionary/dict_importer.rs b/lib/src/dictionary/dict_importer.rs new file mode 100644 index 0000000..5bec64b --- /dev/null +++ b/lib/src/dictionary/dict_importer.rs @@ -0,0 +1,59 @@ +use std::sync::Arc; + +use crate::common::traits::{DictRepository, DictSource}; + +pub struct DictImporter { + repo: Arc, + batch_size: usize, +} + +impl DictImporter { + pub fn new(repo: Arc) -> Self { + Self { + repo, + batch_size: 1000, // reasonable default + } + } + + pub fn with_batch_size(mut self, batch_size: usize) -> Self { + self.batch_size = batch_size; + self + } + + pub async fn import(&self, mut source: impl DictSource) -> Result<(), anyhow::Error> { + // 1. Ensure Dict exists (Logic: Create if new, or maybe clear existing?) + self.repo.create_dict().await?; + + let mut batch = Vec::with_capacity(self.batch_size); + + // 2. Stream data + while let Some(result) = source.next_entry() { + match result { + Ok(entry) => { + // Optional: Domain Validation logic could go here + // if entry.text.is_empty() { continue; } + + batch.push(entry); + + // 3. Batch Write + if batch.len() >= self.batch_size { + self.repo.save_entries(&batch).await?; + batch.clear(); + } + } + Err(e) => { + // Logic: Do we abort on malformed JSON or log and continue? + // Here we abort for safety. + return Err(e); + } + } + } + + // 4. Flush remaining + if !batch.is_empty() { + self.repo.save_entries(&batch).await?; + } + + Ok(()) + } +} diff --git a/lib/src/dictionary/infrastructure.rs b/lib/src/dictionary/infrastructure.rs new file mode 100644 index 0000000..cbff865 --- /dev/null +++ b/lib/src/dictionary/infrastructure.rs @@ -0,0 +1,2 @@ +pub mod json_file_dict_source; +pub mod sqlite_dict_repository; diff --git a/lib/src/dictionary/infrastructure/json_file_dict_source.rs b/lib/src/dictionary/infrastructure/json_file_dict_source.rs new file mode 100644 index 0000000..b7b3dcd --- /dev/null +++ b/lib/src/dictionary/infrastructure/json_file_dict_source.rs @@ -0,0 +1,85 @@ +use crate::common::entities::DictEntry; +use crate::common::traits::DictSource; +use serde::Deserialize; +use std::collections::HashMap; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; + +// The "Wire Format". +// It exists ONLY here to map external JSON names to internal Entity names. +#[derive(Deserialize)] +struct JsonEntry { + word: String, + metadata: Option>, +} + +pub struct JsonFileDictSource { + entries: Vec, + current_index: usize, + next_id: u32, +} + +impl JsonFileDictSource { + pub fn new>(path: P) -> anyhow::Result { + let file = File::open(path)?; + let reader = BufReader::new(file); + + // Parse as JSON array + let json_entries: Vec = serde_json::from_reader(reader)?; + + // Convert to DictEntry with auto-generated IDs + let mut entries = Vec::new(); + for (index, json_entry) in json_entries.into_iter().enumerate() { + let id = (index + 1) as u64; // Auto-generate ID starting from 1 + + // Convert metadata from serde_json::Value to HashMap + let metadata = if let Some(meta) = json_entry.metadata { + meta.into_iter() + .map(|(k, v)| { + ( + k, + match v { + serde_json::Value::String(s) => s, + _ => v.to_string(), + }, + ) + }) + .collect() + } else { + HashMap::new() + }; + + entries.push(DictEntry { + id: Some(id), + text: json_entry.word, + metadata, + }); + } + + let entries_len = entries.len(); + Ok(Self { + entries, + current_index: 0, + next_id: (entries_len + 1) as u32, + }) + } + + pub fn new_with_existing_ids>(path: P, start_id: u32) -> anyhow::Result { + let mut source = Self::new(path)?; + source.next_id = start_id; + Ok(source) + } +} + +impl DictSource for JsonFileDictSource { + fn next_entry(&mut self) -> Option> { + if self.current_index < self.entries.len() { + let entry = self.entries[self.current_index].clone(); + self.current_index += 1; + Some(Ok(entry)) + } else { + None + } + } +} diff --git a/lib/src/dictionary/infrastructure/sqlite_dict_repository.rs b/lib/src/dictionary/infrastructure/sqlite_dict_repository.rs new file mode 100644 index 0000000..48f0e93 --- /dev/null +++ b/lib/src/dictionary/infrastructure/sqlite_dict_repository.rs @@ -0,0 +1,231 @@ +use crate::common::entities::{Dict, DictEntry}; +use crate::common::errors::RepositoryError; +use crate::common::traits::DictRepository; +use futures::TryStreamExt; +use futures::stream::BoxStream; + +use sqlx::{Row, SqlitePool, sqlite::SqliteConnectOptions}; +use std::collections::HashMap; +use std::str::FromStr; + +#[derive(sqlx::FromRow)] +struct SqliteEntryDto { + id: i64, + text: String, + // sqlx reads the DB column into this specific wrapper + metadata: sqlx::types::Json>, +} + +// Mapper: DTO -> Domain Entity +impl From for DictEntry { + fn from(dto: SqliteEntryDto) -> Self { + Self { + id: Some(dto.id as u64), + text: dto.text, + // Unwrap the sqlx wrapper to get the inner HashMap + metadata: dto.metadata.0, + } + } +} + +// --- REPOSITORY IMPLEMENTATION --- + +#[derive(Clone)] +pub struct SqliteDictRepository { + pool: SqlitePool, + dict_name: String, +} + +impl SqliteDictRepository { + pub async fn new(database_url: &str) -> Result { + let options = SqliteConnectOptions::from_str(database_url) + .map_err(|_| RepositoryError::ConnectionFailed)? + .create_if_missing(true); + + let pool = SqlitePool::connect_with(options) + .await + .map_err(|_| RepositoryError::ConnectionFailed)?; + + // Ensure tables exist with proper Normalization and Constraints + sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS dictionaries ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + + CREATE TABLE IF NOT EXISTS entries ( + id INTEGER PRIMARY KEY, + dictionary_id INTEGER NOT NULL, + text TEXT NOT NULL, + metadata TEXT, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(dictionary_id) REFERENCES dictionaries(id) ON DELETE CASCADE, + -- This constraint allows us to update existing words instead of duplicating them + UNIQUE(dictionary_id, text) + ); + "#, + ) + .execute(&pool) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + + Ok(Self { + pool: pool, + dict_name: "default_dict".into(), + }) + } + + // Helper: Resolve dictionary name to ID + async fn get_dict_id(&self) -> Result { + let row = sqlx::query("SELECT id FROM dictionaries WHERE name = ?") + .bind(&self.dict_name) + .fetch_optional(&self.pool) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + + match row { + Some(r) => Ok(r.get("id")), + None => Err(RepositoryError::NotFound(self.dict_name.clone())), + } + } +} + +#[async_trait::async_trait] +impl DictRepository for SqliteDictRepository { + async fn create_dict(&self) -> Result<(), RepositoryError> { + sqlx::query("INSERT OR IGNORE INTO dictionaries (name) VALUES (?)") + .bind(&self.dict_name) + .execute(&self.pool) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + Ok(()) + } + + fn use_dict(&mut self, name: &str) { + self.dict_name = name.to_string(); + } + + async fn save_entries(&self, entries: &[DictEntry]) -> Result<(), RepositoryError> { + let mut tx = self + .pool + .begin() + .await + .map_err(|_| RepositoryError::ConnectionFailed)?; + + // 1. Get Dict ID + let dict_id_row = sqlx::query("SELECT id FROM dictionaries WHERE name = ?") + .bind(&self.dict_name) + .fetch_optional(&mut *tx) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + + let dict_id: i64 = match dict_id_row { + Some(row) => row.get("id"), + None => return Err(RepositoryError::NotFound(self.dict_name.clone())), + }; + + // 2. Batch Upsert + for entry in entries { + // We must wrap the HashMap in sqlx::types::Json so SQLx knows how to serialize it + let meta_json = sqlx::types::Json(&entry.metadata); + + sqlx::query( + r#" + INSERT INTO entries (dictionary_id, text, metadata) + VALUES (?, ?, ?) + ON CONFLICT(dictionary_id, text) DO UPDATE SET + metadata = excluded.metadata, + updated_at = CURRENT_TIMESTAMP + "#, + ) + .bind(dict_id) + .bind(&entry.text) + .bind(meta_json) + .execute(&mut *tx) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + } + + tx.commit() + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + Ok(()) + } + + async fn fetch_many(&self, limit: usize, offset: usize) -> Result { + // Get Dict ID + let dict_id = self.get_dict_id().await?; + + // Query (Reading into the DTO) + let dtos = sqlx::query_as::<_, SqliteEntryDto>( + r#" + SELECT id, text, metadata + FROM entries + WHERE dictionary_id = ? + LIMIT ? OFFSET ? + "#, + ) + .bind(dict_id) + .bind(limit as u32) + .bind(offset as u32) + .fetch_all(&self.pool) + .await + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + + // 4. Convert DTOs to Domain Dict + let mut entries_map = HashMap::new(); + for dto in dtos { + let entry: DictEntry = dto.into(); // Converts DTO -> Entity + + // We safely unwrap because the DB guarantees an ID exists + if let Some(id) = entry.id { + entries_map.insert(id, entry); + } + } + + Ok(Dict { + name: self.dict_name.clone(), + entries: entries_map, + }) + } + + async fn stream_batches( + &self, + batch_size: usize, + ) -> Result, RepositoryError>>, RepositoryError> { + // 1. Resolve ID first + let dict_id = self.get_dict_id().await?; + + // 2. Create the base query stream. + // We do NOT use limit/offset. We let the DB stream rows via a cursor. + let query_stream = sqlx::query("SELECT text FROM entries WHERE dictionary_id = ?") + .bind(dict_id) + .fetch(&self.pool); + + // 3. Transform the stream using Functional combinators + let stream = query_stream + // Map SQLx errors to Domain errors + .map_err(|e| RepositoryError::StorageError(e.to_string())) + // Extract the String from the Row + .and_then(|row| async move { + // 'text' is the column name + let text: String = row + .try_get("text") + .map_err(|e| RepositoryError::StorageError(e.to_string()))?; + Ok(text) + }) + // Group items into vectors of size `batch_size` + .try_chunks(batch_size) + // try_chunks returns a specific error type on failure, map it back + .map_err(|e| { + // logic to handle leftover elements if error occurs, + // but for simplicity, we treat stream errors as fatal here + RepositoryError::StorageError(e.to_string()) + }); + + // 4. Box the stream to erase the complex iterator type (Type Erasure) + Ok(Box::pin(stream)) + } +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs new file mode 100644 index 0000000..33fc17d --- /dev/null +++ b/lib/src/lib.rs @@ -0,0 +1,20 @@ +// pub mod application; +// pub mod core; +// pub mod infrastructure; +// pub mod presentation; + +// pub use self::application::config; +// pub use self::application::services::DictImporter; +// pub use self::core::system; +// pub use self::core::traits; + +mod common; +mod dictionary; +pub mod sys_major; + +pub use self::common::DictRepository; +pub use self::common::SystemDecoder; +pub use self::common::SystemEncoder; +pub use self::dictionary::DictImporter; +pub use self::dictionary::JsonFileDictSource; +pub use self::dictionary::SqliteDictRepository; diff --git a/lib/src/sys_major.rs b/lib/src/sys_major.rs new file mode 100644 index 0000000..b2df791 --- /dev/null +++ b/lib/src/sys_major.rs @@ -0,0 +1,12 @@ +pub mod decoder; +pub mod encoder; +pub mod lvmap; +pub mod rules_en; // TODO: pub? +pub mod rules_pl; // TODO: pub? + +pub use self::decoder::Decoder; +pub use self::encoder::Encoder; +pub use self::lvmap::LenValueMap; // TODO: pub? + +#[cfg(test)] +mod decoder_tests; diff --git a/lib/src/sys_major/decoder.rs b/lib/src/sys_major/decoder.rs new file mode 100644 index 0000000..2324979 --- /dev/null +++ b/lib/src/sys_major/decoder.rs @@ -0,0 +1,122 @@ +use crate::common::{entities::DecodedValue, errors::CodecError, traits::SystemDecoder}; + +#[derive(Debug, Default, Clone)] +pub struct Rule { + pub phoneme_in: String, + pub phoneme_out: String, + + pub not_before: Vec, + pub not_after: Vec, + + pub only_before: Vec, + pub only_after: Vec, +} + +impl Rule { + pub fn into_lowercase(self) -> Self { + Rule { + phoneme_in: self.phoneme_in.to_lowercase(), + phoneme_out: self.phoneme_out.to_lowercase(), + not_before: Self::lower_vec(self.not_before), + not_after: Self::lower_vec(self.not_after), + only_before: Self::lower_vec(self.only_before), + only_after: Self::lower_vec(self.only_after), + } + } + + fn lower_vec(vec: Vec) -> Vec { + vec.into_iter().map(|s| s.to_lowercase()).collect() + } +} + +pub type Rules = Vec; +// pub struct rules { +// name: String, +// entries: Rules, +// } + +/// (index, decoded value) +type RuleMatches = Vec<(usize, String)>; + +pub struct Decoder { + rules: Rules, +} + +impl Decoder { + pub fn new(rules: Rules) -> Self { + Decoder { + rules: Decoder::to_lower_rules(rules), + } + } + + fn to_lower_rules(rules: Rules) -> Rules { + rules + .into_iter() + .map(|entry| entry.into_lowercase()) + .collect() + } + + fn match_entry(&self, entry: &Rule, word: &str) -> RuleMatches { + word.match_indices(&entry.phoneme_in) + .filter(|(index, _)| self.is_context_matched(&entry, &word, *index)) + .map(|(index, _)| (index, entry.phoneme_out.clone())) + .collect() + } + + fn is_context_matched(&self, entry: &Rule, word: &str, index: usize) -> bool { + let before_context = &word[..index]; + let after_context = &word[index + entry.phoneme_in.len()..]; + // dbg!(&before_context); + // dbg!(&after_context); + + if entry + .not_after + .iter() + .any(|prefix| before_context.ends_with(prefix)) + { + return false; + } + + if entry + .not_before + .iter() + .any(|suffix| after_context.starts_with(suffix)) + { + return false; + } + + if !entry.only_after.is_empty() + && entry + .only_after + .iter() + .all(|prefix| !before_context.ends_with(prefix)) + { + return false; + } + + if !entry.only_before.is_empty() + && entry + .only_before + .iter() + .all(|suffix| !after_context.starts_with(suffix)) + { + return false; + } + + true + } +} + +impl SystemDecoder for Decoder { + fn decode(&self, word: &str) -> Result { + let mut matches: RuleMatches = self + .rules + .iter() + .flat_map(|entry| self.match_entry(&entry, &word.to_lowercase())) + .collect(); + + matches.sort_by_key(|&(pos, _)| pos); + let num_str: String = matches.into_iter().map(|(_, value)| value).collect(); + DecodedValue::new(num_str) + } +} diff --git a/lib/src/sys_major/decoder_tests.rs b/lib/src/sys_major/decoder_tests.rs new file mode 100644 index 0000000..debc436 --- /dev/null +++ b/lib/src/sys_major/decoder_tests.rs @@ -0,0 +1,134 @@ +use super::decoder::{Decoder, Rule, Rules}; +use crate::common::traits::SystemDecoder; + +#[cfg(test)] +mod tests { + use super::*; + + fn create_single_rules() -> Rules { + vec![Rule { + phoneme_in: "B".to_string(), + phoneme_out: "2".to_string(), + not_after: vec!["Y".to_string()], + not_before: vec!["X".to_string()], + only_after: vec!["A".to_string()], + only_before: vec!["C".to_string()], + }] + } + + fn create_single_rules_min() -> Rules { + vec![Rule { + phoneme_in: "B".to_string(), + phoneme_out: "2".to_string(), + ..Default::default() + }] + } + + fn create_double_rules() -> Rules { + vec![ + Rule { + phoneme_in: "CD".to_string(), + phoneme_out: "2".to_string(), + not_after: vec!["00".to_string(), "YZ".to_string()], + not_before: vec!["11".to_string(), "WX".to_string()], + only_after: vec!["22".to_string(), "AB".to_string()], + only_before: vec!["33".to_string(), "EF".to_string()], + }, + Rule { + phoneme_in: "MN".to_string(), + phoneme_out: "3".to_string(), + ..Default::default() + }, + ] + } + + #[test] + fn test_single_symbol_encoding_only_before_only_after_matched() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("ABC").unwrap(); + assert_eq!(output, "2") + } + + #[test] + fn test_double_symbol_encoding_only_before_only_after_matched() { + let decoder = Decoder::new(create_double_rules()); + let output = decoder.decode("ABCDEF").unwrap(); + assert_eq!(output, "2") + } + + #[test] + fn test_single_symbol_encoding_only_before_not_matched_with_other() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("DBC").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_double_symbol_encoding_only_before_not_matched_with_other() { + let decoder = Decoder::new(create_double_rules()); + let output = decoder.decode("AACDEE").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_case_insensitivity() { + let decoder = Decoder::new(create_double_rules()); + let output = decoder.decode("abcdef").unwrap(); + assert_eq!(output, "2") + } + + #[test] + fn test_single_symbol_encoding_only_before_not_matched_with_empty() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("BC").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_single_symbol_encoding_only_before_not_matched_with_not_before() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("XBC").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_single_symbol_encoding_only_after_not_matched_with_other() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("ABD").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_single_symbol_encoding_only_after_not_matched_with_empty() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("AB").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_single_symbol_encoding_only_after_not_matched_with_not_after() { + let decoder = Decoder::new(create_single_rules()); + let output = decoder.decode("ABY").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_single_symbol_encoding_empty_before_after_matched_with_empty() { + let decoder = Decoder::new(create_single_rules_min()); + let output = decoder.decode("B").unwrap(); + assert_eq!(output, "2") + } + + #[test] + fn test_single_symbol_encoding_empty_before_after_matched_with_others() { + let decoder = Decoder::new(create_single_rules_min()); + let output = decoder.decode("AXBYC").unwrap(); + assert_eq!(output, "2") + } + #[test] + fn test_encoding_multiple_phonemes() { + let decoder = Decoder::new(create_double_rules()); + let output = decoder.decode("VvmNabCd33mn00CD22cdefmn").unwrap(); + assert_eq!(output, "32323") + } +} diff --git a/lib/src/sys_major/encoder.rs b/lib/src/sys_major/encoder.rs new file mode 100644 index 0000000..c90d537 --- /dev/null +++ b/lib/src/sys_major/encoder.rs @@ -0,0 +1,179 @@ +use crate::common::{ + entities::{EncodedPart, EncodedSplit, EncodedValue}, + errors::CodecError, + traits::*, +}; + +use super::lvmap::LenValueMap; + +#[derive(Debug)] +pub struct Encoder { + lv_map: LenValueMap, +} + +impl Encoder { + pub fn new(lv_map: LenValueMap) -> Self { + Encoder { lv_map } + } +} + +impl SystemEncoder for Encoder { + fn initialize(&self) -> Result<(), CodecError> { + Ok(()) + } + + fn encode(&self, input: &str) -> Result { + let size = input.chars().count(); + let max_mask: usize = (1 << (size - 1)) - 1; + + let indices: Vec = input.char_indices().map(|(i, _)| i).collect(); + let mut results = Vec::with_capacity(max_mask); + + for mask in 0..=max_mask { + let mut parts: Vec = Vec::new(); + let mut last_split = input.char_indices().count(); // we go from right to left to start with the longest parts + + // Iterate through the mask bits to find where to split + for i in 0..size - 1 { + // Check if the i-th bit is set + if (mask >> i) & 1 == 1 { + // The split corresponds to the byte index of the (i+1)-th character + let split_idx = indices[indices.len() - i - 1]; + parts.push(input[split_idx..last_split].to_string()); + last_split = split_idx; + } + } + // Push the remaining part of the string + parts.push(input[..last_split].to_string()); + + let mut all_matched = true; + let mut split = EncodedSplit::new(); + parts.reverse(); + + for part in &parts { + let Ok(num_part) = part.parse::() else { + all_matched = false; + break; + }; + let Some(words) = self.lv_map.get(part.len() as u8, num_part) else { + all_matched = false; + break; + }; + split.push(EncodedPart { + value: num_part, + words: words.clone(), + }); + } + + if all_matched { + results.push(Partition { + value: split, + // To find the "most equal" size, we minimize the sum of squared lengths. + // (This mathematically minimizes variance without needing floating point math) + sum_sq_len: parts.iter().map(|p| p.chars().count().pow(2)).sum(), + }); + } + + // Calculate metrics for sorting + // let num_parts = parts.len(); + + // // To find the "most equal" size, we minimize the sum of squared lengths. + // // (This mathematically minimizes variance without needing floating point math) + // let sum_sq_len: usize = parts.iter().map(|p| p.chars().count().pow(2)).sum(); + + // if let Some(words) = self.lv_map.get(size as u8, input.parse().unwrap()) { + // results.push(Partition { + // parts: words.clone(), + // sum_sq_len, + // }); + // } + } + + // Ok(EncodedValue::new(words)) + // Sort by: + // 1. Fewer parts first (1 part, then 2 parts...) + // 2. Most equal lengths (lower sum of squared lengths is more balanced) + // 3. TODO: Lexicographically (for deterministic stability)? + results.sort_by(|a, b| { + a.value + .len() + .cmp(&b.value.len()) + .then(a.sum_sq_len.cmp(&b.sum_sq_len)) + }); + + // Extract just the strings + let split_results = results.into_iter().map(|p| p.value).collect(); + Ok(EncodedValue::new(split_results)) + } +} + +// A helper struct to keep the split variant and its sort metrics together +struct Partition { + value: EncodedSplit, + sum_sq_len: usize, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_encode_as_single_length_result() { + let mut lvmap = LenValueMap::new(); + lvmap.push(3, 123, "test_123"); + lvmap.push(3, 345, "test_345_1"); + lvmap.push(3, 345, "test_345_2"); + lvmap.push(3, 678, "test_678"); + let encoder = Encoder::new(lvmap); + let result = encoder.encode("345").unwrap(); + + assert_eq!(result.len(), 1); // single split + assert_eq!(result[0].len(), 1); // single part + assert_eq!(result[0][0].value, 345); + assert_eq!(result[0][0].words.len(), 2); // two words + assert_eq!(result[0][0].words[0], "test_345_1"); + assert_eq!(result[0][0].words[1], "test_345_2"); + } + + #[test] + fn test_encode_as_all_lengths() { + let mut lvmap = LenValueMap::new(); + lvmap.push(1, 0, "test_0"); + lvmap.push(1, 9, "test_9"); + lvmap.push(1, 8, "test_8"); + lvmap.push(1, 7, "test_7"); + lvmap.push(2, 98, "test_98"); + lvmap.push(2, 87, "test_87"); + lvmap.push(3, 987, "test_987"); + lvmap.push(3, 876, "test_876"); + + let encoder = Encoder::new(lvmap); + let result = encoder.encode("987").unwrap(); + + assert_eq!(result.len(), 4); // 987, 98|7, 9|87, 9|8|7 + assert_eq!(result[0].len(), 1); // 987 + + assert_eq!(result[0][0].words.len(), 1); + assert_eq!(result[0][0].words[0], "test_987"); + + assert_eq!(result[1].len(), 2); // 98|7 + assert_eq!(result[1][0].words.len(), 1); + assert_eq!(result[1][0].words[0], "test_98"); + assert_eq!(result[1][1].words.len(), 1); + assert_eq!(result[1][1].words[0], "test_7"); + + assert_eq!(result[2].len(), 2); // 9|87 + assert_eq!(result[2][0].words.len(), 1); + assert_eq!(result[2][0].words[0], "test_9"); + assert_eq!(result[2][1].words.len(), 1); + assert_eq!(result[2][1].words[0], "test_87"); + + assert_eq!(result[3].len(), 3); // 9|8|7 + assert_eq!(result[3][0].words.len(), 1); + assert_eq!(result[3][0].words[0], "test_9"); + assert_eq!(result[3][1].words.len(), 1); + assert_eq!(result[3][1].words[0], "test_8"); + assert_eq!(result[3][2].words.len(), 1); + assert_eq!(result[3][2].words[0], "test_7"); + } +} diff --git a/lib/src/sys_major/lvmap.rs b/lib/src/sys_major/lvmap.rs new file mode 100644 index 0000000..bb68fb2 --- /dev/null +++ b/lib/src/sys_major/lvmap.rs @@ -0,0 +1,351 @@ +use crate::common::{ + SystemDecoder, + entities::DecodedLength, + errors::{CodecError, RepositoryError}, +}; +use futures::{Stream, StreamExt}; +use std::{collections::HashMap, num::ParseIntError}; +use thiserror::Error; + +// We store words by encoded number length, then encoded value +// Example: +// root: +// - 3: +// - 750: +// - word: klasa +// - word: gilza +// - 849: +// - word: farba +// - 2: +// - 45: +// - word: oral + +#[derive(Error, Debug)] +pub enum LenValueMapError { + #[error("value parsing error: {0}")] + Parse(#[from] ParseIntError), + + #[error(transparent)] + Codec(#[from] CodecError), + + #[error(transparent)] + Repository(#[from] RepositoryError), + + #[error("unable to build encoder data: {0}")] + Build(String), +} + +type DecodedNumber = u64; +pub type LenValueData = HashMap>>; + +#[derive(Debug, Default, Clone)] +pub struct LenValueMap { + data: LenValueData, +} + +impl LenValueMap { + pub fn new() -> Self { + Self::default() + } + + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn into_data(self) -> LenValueData { + self.data + } + + pub fn push(&mut self, len: u8, num: DecodedNumber, word: impl Into) -> &mut Self { + self.data + .entry(DecodedLength::from(len)) + .or_insert_with(HashMap::new) + .entry(num) + .or_insert_with(Vec::new) + .push(word.into()); + self + } + + pub fn get(&self, len: u8, num: DecodedNumber) -> Option<&Vec> { + self.data.get(&DecodedLength::from(len))?.get(&num) + } + + pub fn insert_words( + &mut self, + words: I, + decoder: &dyn SystemDecoder, + ) -> Result<(), LenValueMapError> + where + I: IntoIterator, + { + for word in words { + if word.is_empty() { + continue; + } + let decoded = decoder.decode(&word)?; + if decoded.is_empty() { + continue; + } + + self.data + .entry(decoded.value_len()?) + .or_default() + .entry(decoded.parse()?) + .or_default() + .push(word); + } + Ok(()) + } + + pub fn from_data(data: LenValueData) -> Self { + Self { data: data } + } + + pub async fn from_stream( + stream: S, + decoder: &dyn SystemDecoder, + ) -> Result + where + // S is a stream of "Result, Error>" + S: Stream, RepositoryError>>, + { + let mut map = LenValueMap::new(); + let mut stream = Box::pin(stream); + + // We stream the batches one by one. + // This ensures only one batch is in memory at a time. + while let Some(batch_result) = stream.next().await { + match batch_result { + Ok(batch) => { + // We delegate to the synchronous logic for the heavy lifting + map.insert_words(batch, decoder)?; + } + Err(e) => { + // Convert RepositoryError to LenValueMapError::Build + return Err(e.into()); + } + } + } + + Ok(map) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::{entities::*, errors::*}; + use futures::stream; + + use std::collections::HashMap; + + use mockall::{mock, predicate::*}; + + const TEST_WORD_1: &str = "test_word_1"; + const TEST_WORD_2: &str = "test_word_2"; + const TEST_WORD_3: &str = "test_word_3"; + const TEST_WORD_4: &str = "test_word_4"; + const TEST_NUM_1: u64 = 12; + const TEST_NUM_2: u64 = 34; + const TEST_NUM_3: u64 = 9876; + const TEST_NUM_1_LEN: DecodedLength = DecodedLength::from(2); + const TEST_NUM_3_LEN: DecodedLength = DecodedLength::from(4); + + fn decoded_value(n: u64) -> DecodedValue { + DecodedValue::new(n.to_string()).unwrap() + } + + fn get_test_dec_map() -> HashMap { + HashMap::from([ + (TEST_WORD_1.to_string(), decoded_value(TEST_NUM_1)), + (TEST_WORD_2.to_string(), decoded_value(TEST_NUM_2)), + (TEST_WORD_3.to_string(), decoded_value(TEST_NUM_3)), + (TEST_WORD_4.to_string(), decoded_value(TEST_NUM_3)), + ]) + } + + fn mock_decoding(word: &str) -> Result { + get_test_dec_map() + .remove(word) + .ok_or_else(|| CodecError::UnexpectedError("".to_string())) + } + + fn get_test_words() -> Vec { + vec![ + TEST_WORD_1.to_string(), + TEST_WORD_2.to_string(), + TEST_WORD_3.to_string(), + TEST_WORD_4.to_string(), + ] + } + + mock! { + pub Decoder {} + impl SystemDecoder for Decoder { + fn decode(&self, word: &str) -> Result; + } + } + + #[test] + fn test_single_word() { + let words = vec![TEST_WORD_1.to_string()]; + let mut decoder = MockDecoder::new(); + decoder + .expect_decode() + .returning(|word| mock_decoding(word)); + + let mut lv_map = LenValueMap::new(); + lv_map.insert_words(words, &decoder).unwrap(); + + let data = lv_map.into_data(); + + assert_eq!(data.len(), 1); + assert!(data.contains_key(&TEST_NUM_1_LEN)); + let data = data.get(&TEST_NUM_1_LEN).unwrap(); + assert!(data.contains_key(&TEST_NUM_1)); + let words = data.get(&TEST_NUM_1).unwrap(); + assert_eq!(words.len(), 1); + assert_eq!(words[0], TEST_WORD_1); + } + + #[test] + fn test_multiple_words() { + let words = get_test_words(); + + let mut decoder = MockDecoder::new(); + decoder + .expect_decode() + .returning(|word| mock_decoding(word)); + + let mut lv_map = LenValueMap::new(); + lv_map.insert_words(words, &decoder).unwrap(); + + let data = lv_map.into_data(); + + assert_eq!(data.len(), 2); // two different lengths + assert!(data.contains_key(&TEST_NUM_1_LEN)); + assert!(data.contains_key(&TEST_NUM_3_LEN)); + let l2 = data.get(&TEST_NUM_1_LEN).unwrap(); + let l4 = data.get(&TEST_NUM_3_LEN).unwrap(); + + assert_eq!(l2.len(), 2); // two numbers + assert_eq!(l4.len(), 1); // one number + assert!(l2.contains_key(&TEST_NUM_1)); + assert!(l2.contains_key(&TEST_NUM_2)); + assert!(l4.contains_key(&TEST_NUM_3)); + + let words = l2.get(&TEST_NUM_1).unwrap(); + assert_eq!(words.len(), 1); + assert_eq!(words[0], TEST_WORD_1); + + let words = l2.get(&TEST_NUM_2).unwrap(); + assert_eq!(words.len(), 1); + assert_eq!(words[0], TEST_WORD_2); + + let words = l4.get(&TEST_NUM_3).unwrap(); + assert_eq!(words.len(), 2); + assert!(words.contains(&TEST_WORD_3.to_string())); + assert!(words.contains(&TEST_WORD_4.to_string())); + } + + #[test] + fn test_skip_empty_decodes() { + let words = vec![TEST_WORD_1.to_string(), TEST_WORD_2.to_string()]; + let mut decoder = MockDecoder::new(); + decoder.expect_decode().returning(|word| { + if word == TEST_WORD_1 { + DecodedValue::new("".to_string()) + } else { + DecodedValue::new(TEST_NUM_2.to_string()) + } + }); + + let mut lv_map = LenValueMap::new(); + lv_map.insert_words(words, &decoder).unwrap(); + + let data = lv_map.into_data(); + + assert_eq!(data.len(), 1); + assert!(data.contains_key(&TEST_NUM_1_LEN)); + let data = data.get(&TEST_NUM_1_LEN).unwrap(); + assert!(data.contains_key(&TEST_NUM_2)); + let words = data.get(&TEST_NUM_2).unwrap(); + assert_eq!(words.len(), 1); + assert_eq!(words[0], TEST_WORD_2); + } + + #[test] + fn test_decoder_error_propagates() { + let mut decoder = MockDecoder::new(); + decoder + .expect_decode() + .returning(|_| Err(CodecError::UnexpectedError("boom".into()))); + + let mut map = LenValueMap::new(); + let result = map.insert_words(vec!["x".into()], &decoder); + + assert!(result.is_err()); + } + + // --- build --- + + #[tokio::test] + async fn test_from_stream_success() { + // 1. Setup Mocks (Same as before) + let mut decoder = MockDecoder::new(); + decoder + .expect_decode() + .returning(|word| mock_decoding(word)); + + // 2. Prepare Data + // We wrap the inner Vecs in Ok() because the stream expects Result, RepositoryError> + let batches = vec![ + Ok(vec![TEST_WORD_1.into(), TEST_WORD_2.into()]), + Ok(vec![TEST_WORD_3.into(), TEST_WORD_4.into()]), + ]; + + // 3. Create a Stream from the Vec + // stream::iter converts an IntoIterator into a Stream + let stream = stream::iter(batches); + + // 4. Inject the stream (Dependency Injection) + let map = LenValueMap::from_stream(stream, &decoder) + .await + .expect("Should build map successfully"); + + // 5. Assertions + let data = map.into_data(); + assert_eq!(data.len(), 2); + assert!(data.contains_key(&TEST_NUM_1_LEN)); + assert!(data.contains_key(&TEST_NUM_3_LEN)); + } + + #[tokio::test] + async fn test_from_stream_failure() { + let mut decoder = MockDecoder::new(); + decoder + .expect_decode() + .returning(|word| mock_decoding(word)); + + let batches = vec![ + Ok(vec![TEST_WORD_1.into()]), + Err(RepositoryError::ConnectionFailed), + Ok(vec![TEST_WORD_3.into()]), + ]; + + let stream = stream::iter(batches); + let result = LenValueMap::from_stream(stream, &decoder).await; + + match result { + // We match specifically on the Repository variant and the ConnectionFailed inner error + Err(LenValueMapError::Repository(RepositoryError::ConnectionFailed)) => { + // Success! The correct error type propagated up. + } + // If it's any other error (including a stringified one), we fail + _ => panic!( + "Expected LenValueMapError::Repository(ConnectionFailed), got {:?}", + result + ), + } + } +} diff --git a/lib/src/sys_major/rules_en.rs b/lib/src/sys_major/rules_en.rs new file mode 100644 index 0000000..78f6cc6 --- /dev/null +++ b/lib/src/sys_major/rules_en.rs @@ -0,0 +1,15 @@ +use super::decoder::{Rule, Rules}; + +pub fn get_rules() -> Rules { + vec![ + Rule { + phoneme_in: "EN".to_string(), + phoneme_out: "2".to_string(), + not_after: vec!["Y".to_string()], + not_before: vec!["X".to_string()], + only_after: vec!["A".to_string()], + only_before: vec!["C".to_string()], + }, + // ...more entries... + ] +} diff --git a/lib/src/sys_major/rules_pl.rs b/lib/src/sys_major/rules_pl.rs new file mode 100644 index 0000000..0cdf587 --- /dev/null +++ b/lib/src/sys_major/rules_pl.rs @@ -0,0 +1,222 @@ +use super::decoder::{Rule, Rules}; + +pub fn get_rules() -> Rules { + vec![ + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "S".to_string(), + phoneme_out: "0".to_string(), + not_before: vec!["I".to_string(), "Z".to_string()], + only_before: vec![], + }, + Rule { + not_after: vec![ + "C".to_string(), + "D".to_string(), + "R".to_string(), + "S".to_string(), + ], + only_after: vec![], + phoneme_in: "Z".to_string(), + phoneme_out: "0".to_string(), + not_before: vec!["I".to_string()], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "T".to_string(), + phoneme_out: "1".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + only_after: vec![], + not_after: vec![], + phoneme_in: "D".to_string(), + phoneme_out: "1".to_string(), + not_before: vec!["Z".to_string(), "Ź".to_string(), "Ż".to_string()], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "N".to_string(), + phoneme_out: "2".to_string(), + not_before: vec!["I".to_string()], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "M".to_string(), + phoneme_out: "3".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "R".to_string(), + phoneme_out: "4".to_string(), + not_before: vec!["Z".to_string()], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "L".to_string(), + phoneme_out: "5".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "J".to_string(), + phoneme_out: "6".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "K".to_string(), + phoneme_out: "7".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "G".to_string(), + phoneme_out: "7".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "F".to_string(), + phoneme_out: "8".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "W".to_string(), + phoneme_out: "8".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "P".to_string(), + phoneme_out: "9".to_string(), + not_before: vec![], + only_before: vec![], + }, + Rule { + not_after: vec![], + only_after: vec![], + phoneme_in: "B".to_string(), + phoneme_out: "9".to_string(), + not_before: vec![], + only_before: vec![], + }, + ] +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::sys_major::Decoder; + use crate::traits::SystemDecoder; + + #[test] + fn test_major_dict_pl_decode_0_1() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("SZSCZ").unwrap(); + assert_eq!(output, "0") + } + + #[test] + fn test_major_dict_pl_decode_0_2() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("SZSICZ").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_major_dict_pl_decode_0_3() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("SZCZRZZCZDZSZ").unwrap(); + assert_eq!(output, "0") + } + + #[test] + fn test_major_dict_pl_decode_0_4() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("SZCZRZZICZDZSZ").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_major_dict_pl_decode_1_1() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("SZTCZ").unwrap(); + assert_eq!(output, "1") + } + + #[test] + fn test_major_dict_pl_decode_1_2() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("DZDŻDŹDDZDŻDŹ").unwrap(); + assert_eq!(output, "1") + } + + #[test] + fn test_major_dict_pl_decode_1_3() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("DZDŻDŹDZDZDŻDŹ").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_major_dict_pl_decode_2_1() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("NINNI").unwrap(); + assert_eq!(output, "2") + } + + #[test] + fn test_major_dict_pl_decode_2_2() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("NININI").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_major_dict_pl_decode_4_1() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("RZRRZ").unwrap(); + assert_eq!(output, "4") + } + + #[test] + fn test_major_dict_pl_decode_4_2() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("RZRZRZ").unwrap(); + assert_eq!(output, "") + } + + #[test] + fn test_major_dict_pl_decode_full_1() { + let decoder = Decoder::new(get_rules()); + let output = decoder.decode("ATADANAMARALAJAKAGAFAWAPABA").unwrap(); + assert_eq!(output, "1123456778899") + } +} diff --git a/resources/dsr1ll70_pl_demo.json b/resources/dsr1ll70_pl_demo.json new file mode 100644 index 0000000..d4514aa --- /dev/null +++ b/resources/dsr1ll70_pl_demo.json @@ -0,0 +1,8612 @@ +[ + { + "word": "to", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "co", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "rok", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "czas", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "człowiek", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "raz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wszystko", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "życie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "dzień", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "miejsce", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "praca", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "osoba", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dziecko", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "coś", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "sprawa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Polska", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pan", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "strona", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "nic", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "świat", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dom", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "koniec", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kobieta", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "chwila", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "miasto", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "głowa", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "oko", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "sposób", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kto", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "słowo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "ręka", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "prawo", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "ktoś", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "droga", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pani", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "część", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "państwo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "sytuacja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kraj", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "rzecz", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "mężczyzna", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "problem", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "stan", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "nikt", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "rodzina", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ojciec", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "historia", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "przypadek", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zmiana", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "władza", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "książka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "głos", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "firma", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "szkoła", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "godzina", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "matka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "uwaga", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "cel", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wojna", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wiek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "środek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "grupa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "temat", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "bóg", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "początek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Warszawa", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "związek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wszyscy", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "pomoc", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "siła", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "przykład", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "miesiąc", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "twarz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "śmierć", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pytanie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "pieniądz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "kościół", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "prawda", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "woda", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ciało", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "powód", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "moment", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "rząd", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "mieszkaniec", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "samochód", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "sąd", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "spotkanie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "myśl", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "informacja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ruch", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "drzwi", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "film", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ulica", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "rozmowa", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "projekt", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "system", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "decyzja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "prezydent", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "działanie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "tydzień", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zdanie", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "możliwość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ziemia", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "kultura", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "rada", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "udział", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "rynek", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "zasada", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "program", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Polak", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "rodzic", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "język", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "mieszkanie", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "noc", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pracownik", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "większość", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "polityka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wynik", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "tysiąc", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Europa", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "rola", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pokój", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "punkt", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dziewczyna", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "zespół", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ustawa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "badanie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "żona", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "okres", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wzgląd", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "góra", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "obraz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "policja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "granica", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "plan", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "autor", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "walka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "serce", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "teren", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wartość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "forma", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "zdjęcie", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ogół", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "dłoń", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "postać", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "ksiądz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "liczba", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "cena", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "fakt", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Jan", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "mama", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "szpital", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "nadzieja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "brak", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "sztuka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "rozwój", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "miłość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "akcja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "gmina", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "podstawa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "syn", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "poziom", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "proces", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "rodzaj", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "budynek", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wniosek", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "noga", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "gra", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Rosja", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wpływ", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "spółka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "mąż", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "minister", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "umowa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "lekarz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "koszt", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "okno", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "okazja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wrażenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "ściana", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "potrzeba", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "szansa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "partia", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "odpowiedź", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "centrum", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kolej", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "pomysł", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "światło", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "relacja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "połowa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "minuta", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "działalność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Paweł", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "szczęście", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "organizacja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kwestia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "prezes", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "członek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kierunek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "budowa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "krok", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "znaczenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wolność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "tekst", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "imię", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "sens", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "brat", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wypadek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dyrektor", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "szef", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "rzeczywistość", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przepis", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "doświadczenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wydarzenie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "powrót", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "córka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ramię", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "telefon", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "środowisko", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "urząd", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "zdrowie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "usta", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "służba", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "list", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "przestrzeń", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "pies", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Andrzej", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wzrok", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ciąg", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zwierzę", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "próba", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "element", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "efekt", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "klub", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "stopień", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pamięć", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "zadanie", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kontakt", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Piotr", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "choroba", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "stanowisko", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kolega", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "przyjaciel", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "dokument", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "PiS", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "tytuł", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "pora", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "nauka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "społeczeństwo", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "obowiązek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pewność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "klasa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "inwestycja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wieczór", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "bezpieczeństwo", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "scena", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "bohater", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "charakter", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wybory", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "krew", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "stół", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "auto", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "medium", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "mecz", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "ramy", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "linia", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "rozwiązanie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ofiara", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "policjant", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "muzyka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "komisja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "palec", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Żyd", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "sklep", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "duch", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "gość", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "siostra", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "właściciel", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "typ", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "źródło", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ochrona", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "drzewo", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zakres", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kierowca", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wysokość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "żołnierz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wiedza", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "łóżko", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "numer", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "włos", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Kraków", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "gazeta", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "nazwa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "materiał", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "powietrze", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wybór", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "polityk", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "klient", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "los", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "przyszłość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "opinia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "las", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "dzieło", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wrzesień", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "warunki", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zakład", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wieś", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "chłopiec", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "bank", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "poczucie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "grudzień", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "sukces", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "pozycja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "instytucja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "jednostka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "znak", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "produkcja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kontrola", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "maj", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "moc", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wiara", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "opowieść", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "nazwisko", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "styczeń", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "współpraca", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "porządek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pole", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "naród", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "marzec", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Niemcy", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "gospodarka", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pacjent", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wzrost", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "złoty", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "chłopak", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "sala", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "pojęcie", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "Anna", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "sieć", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "skutek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "model", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wersja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "milion", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "sierpień", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "czerwiec", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "oddział", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "mowa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ból", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "przedstawiciel", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "dana", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "termin", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "teatr", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Adam", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Marek", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "uczeń", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kwiecień", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "profesor", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "metr", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "emocja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "interes", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przedmiot", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "postępowanie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kuchnia", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "racja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Jezus", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "zachód", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "funkcja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "październik", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "spojrzenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "usługa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przyczyna", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "praktyka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "produkt", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "lipiec", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wiersz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "okolica", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "lista", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "perspektywa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "powiat", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kwota", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "stosunek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "karta", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "radny", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "listopad", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "dowód", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "świadomość", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "kara", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Maria", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "powieść", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "spokój", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wyrok", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "sprzedaż", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "artysta", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ślad", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "widok", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "słońce", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wątpliwość", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "premier", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "unia", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "niebo", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "obszar", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "tradycja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "energia", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "nagroda", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "obywatel", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "literatura", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "sen", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zachowanie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pojazd", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "nauczyciel", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Michał", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "USA", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "dodatek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "reszta", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Krzysztof", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ośrodek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dziennikarz", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Tomasz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "pismo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "obiekt", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "realizacja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "trakt", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "podróż", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "błąd", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "natura", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "skóra", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zdarzenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "zakup", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kolor", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "ocena", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "artykuł", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "metoda", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "impreza", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "plac", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zarząd", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "zagrożenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "para", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "pociąg", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "przekonanie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "nos", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "uczestnik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "biuro", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "obrona", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "istota", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wiadomość", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "różnica", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "uniwersytet", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "gwiazda", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "wsparcie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "region", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "podatek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "płyty", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "obecność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Jerzy", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "uśmiech", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "układ", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "sędzia", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "styl", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Niemiec", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "idea", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "pisarz", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "całość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "konkurs", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Marcin", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "warunek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "dobro", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "opieka", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "obóz", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wspomnienie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "trasa", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zabawa", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "miara", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "uczucie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "niedziela", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "przeszłość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wizyta", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "zgoda", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Stanisław", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dół", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wojsko", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "oferta", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wspólnota", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "luty", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "ministerstwo", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "czytelnik", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "doktor", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "stacja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dusza", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "święto", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "drużyna", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "sprawiedliwość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "czoło", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "kryzys", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wino", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "babcia", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Robert", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "strach", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "konsekwencja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "atak", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "studia", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "morze", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "koncert", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ucho", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Ewa", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wywiad", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "płyta", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Szczecin", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Jacek", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "prokuratura", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "towarzystwo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "broń", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "dyskusja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "etap", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "muzeum", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "alkohol", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "budżet", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "utwór", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "bok", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Ukraina", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "kawa", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dziewczynka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "konflikt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "procent", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "fragment", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "więzienie", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "podłoga", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wizja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "telewizja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "armia", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "propozycja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zainteresowanie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "fundusz", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "jazda", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "treść", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "sezon", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "podmiot", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kształt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "park", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "król", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "suma", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "stopa", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "cisza", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "młodzież", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Józef", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "sobota", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wyjazd", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dostęp", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "poeta", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "facet", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "znajomy", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "radość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "pokolenie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przedsiębiorca", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "akt", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wnętrze", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kategoria", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "poseł", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "dźwięk", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "rewolucja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wola", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "robota", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "południe", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "odpowiedzialność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "świadek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "ogień", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "skład", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kandydat", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wymiar", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Kaczyński", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "papier", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "skala", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "okoliczność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "struktura", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "rzeka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "tajemnica", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "twórca", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wiatr", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "tata", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ilość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "sąsiad", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Francja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zarzut", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "stolica", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "reakcja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "but", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "województwo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wina", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "student", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "kawałek", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "papież", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "widzenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "powierzchnia", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "funkcjonariusz", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "seks", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Tadeusz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "urzędnik", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "raport", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "hotel", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Gdańsk", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ogród", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "szczyt", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dziadek", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "kwiat", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "partner", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "sprzęt", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "kino", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "koło", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "jakość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "postawa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "solidarność", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "analiza", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "zjawisko", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "placówka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "organ", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wyraz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wystawa", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "strefa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "sejm", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Wrocław", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "fala", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "konieczność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kariera", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wschód", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kłopot", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "przemysł", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "fundacja", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "towar", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "aktor", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "kredyt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "krzyż", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "mistrz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "euro", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "narzędzie", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "pogląd", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "tył", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "lokal", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "cień", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "zapach", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "małżeństwo", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "PO", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "stowarzyszenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kontekst", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kamień", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "urządzenie", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "internet", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "tłum", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wyjście", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "cóż", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "grunt", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "rzecznik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Karol", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Jarosław", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "korytarz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "tożsamość", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "tło", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wydział", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "strata", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "instytut", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pracodawca", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "radio", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "odcinek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ryzyko", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "mur", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "kampania", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "producent", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zwycięstwo", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "lider", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "UE", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "cecha", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "gaz", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "powstanie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "opozycja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "pomieszczenie", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "piątek", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kilometr", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Agnieszka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "sekunda", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "fotel", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "gatunek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "transport", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "lato", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "pierś", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "gest", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "biskup", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "ząb", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ekspert", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pas", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "trener", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Poznań", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zawodnik", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "szczegół", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "lek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "brama", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "blok", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "burmistrz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "prokurator", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "bilet", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "bieg", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "silnik", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "nieruchomość", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "brzeg", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "salon", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "śmiech", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "opłata", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "cud", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "łza", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ton", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "piłka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "przerwa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "hasło", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Jakub", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pełnia", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "baza", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "dach", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "koncepcja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "operacja", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zakaz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kot", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "festiwal", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "demokracja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "religia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kurs", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "liga", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "krzesło", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "marzenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Chiny", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "wiosna", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Moskwa", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "zima", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "autobus", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "jedzenie", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "edukacja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "spór", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "porozumienie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zajęcia", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "poezja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "ochota", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "technologia", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "umysł", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "samorząd", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kartka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Alicja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "czynność", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Stany", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "przemoc", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "dochód", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "połączenie", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "komórka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "maszyna", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "butelka", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "marka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "samolot", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "teoria", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ubranie", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wypowiedź", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "piosenka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "umiejętność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "reguła", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "koń", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "podział", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "inicjatywa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "biznes", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ekran", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "cmentarz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "kolano", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wzór", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "adres", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Ameryka", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "odpad", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wróg", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ptak", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "kieszeń", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "konferencja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "zawód", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "protest", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dziś", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "schody", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "trud", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "dziennik", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "papieros", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Wojciech", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "szacunek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "klucz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "atmosfera", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "symbol", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "sport", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "przewodniczący", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "mózg", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "koleżanka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "platforma", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pomnik", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wyspa", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "przeciwnik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "widz", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "śledztwo", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "owoc", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "przedsiębiorstwo", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "roślina", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "przyjemność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wyzwanie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "argument", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kolejka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "restauracja", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "opis", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wydatek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "piwo", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "kąt", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ciąża", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "komitet", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Chrystus", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dzielnica", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "poniedziałek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "myślenie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "uchwała", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "zło", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "konto", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "grób", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "strategia", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "masa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "pasażer", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "modlitwa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wynagrodzenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Łódź", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ścieżka", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "miejscowość", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "statek", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dziedzina", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "lęk", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "setka", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "twórczość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "remont", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "sfera", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "obawa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "komputer", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "śnieg", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "oficer", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "reforma", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "piętro", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zbrodnia", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wyprawa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "seria", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "branża", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Stefan", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "komenda", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "osiedle", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "majątek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "gabinet", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "mechanizm", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "portal", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "świadczenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "katastrofa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "ślub", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Rosjanin", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Maciej", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Grzegorz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "organizm", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wyobraźnia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "deszcz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wakacje", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "mięso", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "ulga", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "komunikacja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Rafał", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "siedziba", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "porównanie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "procedura", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "gospodarz", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "jesień", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zdolność", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "specjalista", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "zamek", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "fotografia", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "uczelnia", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "pałac", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Paryż", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "dolar", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wysiłek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zbiór", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "lektura", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "biblioteka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "stolik", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Lech", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "założenie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "port", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "klatka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "scenariusz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "norma", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "handel", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "cokolwiek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "podejście", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "agencja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Mateusz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "herbata", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zapis", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "fabryka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "grzech", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "mapa", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "napięcie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "próg", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "społeczność", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "aktywność", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "rozporządzenie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Joanna", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "chęć", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "wejście", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "szyba", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "nastrój", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kasa", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "piłkarz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "działacz", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Janusz", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "oddech", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "organizator", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "robotnik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "izba", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "lud", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "sygnał", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "milczenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "otoczenie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "spacer", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "msza", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "szereg", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "sesja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Kazimierz", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "prośba", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "obiad", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "dzieciństwo", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kamienica", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "łazienka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Małgorzata", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pobyt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "inwestor", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "czyn", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "filozofia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "emerytura", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "elita", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "straż", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zaufanie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "lekcja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zabieg", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "sektor", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "zysk", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wyjątek", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kamera", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "wymiana", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "książę", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "spadek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zwrot", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dekada", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "korzyść", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "smak", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "obsługa", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zamiar", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "misja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wielkość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "własność", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "brzuch", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "sprawca", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "most", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "oczekiwanie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "interpretacja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "cierpienie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "reżyser", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "przestępstwo", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Łukasz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "mnóstwo", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Zbigniew", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "komentarz", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "epoka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "księga", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "galeria", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "przód", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kość", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "tor", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "ojczyzna", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "inny", + "metadata": { + "type": "noun", + "score": 1 + } + }, + { + "word": "Śląsk", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "test", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "bramka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ekipa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "szyja", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "miasteczko", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "data", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "rezultat", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "skarb", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "generał", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "czynnik", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "naukowiec", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "chleb", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "stawka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "północ", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "administracja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "finanse", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "publikacja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Henryk", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "PRL", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "spektakl", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "rower", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Aleksander", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Wisła", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "prasa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "status", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przyjaciółka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dworzec", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pragnienie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kierownik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "warstwa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "mina", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "uroczystość", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "standard", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kapitan", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ciemność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "ryba", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "infrastruktura", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "krytyka", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "debata", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "policzek", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "publiczność", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "płeć", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "prędkość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "śmieć", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "lotnisko", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "biurko", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ucieczka", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "upadek", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kapitał", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Katowice", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "tragedia", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Monika", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "dwór", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Katarzyna", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "ubezpieczenie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "rozdział", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "tryb", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "kibic", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "czwartek", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "temperatura", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wizerunek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "chłop", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "rachunek", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "RP", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Antoni", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "środa", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "napis", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "koronawirus", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "technika", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przedszkole", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pogoda", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wybuch", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "sumienie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "prezent", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Marta", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "taniec", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "spodnie", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "nóż", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "cykl", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "finał", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "gracz", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "proboszcz", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Mikołaj", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "parlament", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "przełom", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "oblicze", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "turysta", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "stadion", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "redakcja", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "lewica", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "konkurencja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "konstrukcja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "węgiel", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "dystans", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "utrata", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przywódca", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "klimat", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "poparcie", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "wątek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "zwolennik", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "konstytucja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "trawa", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "opór", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "gospodarstwo", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "gardło", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "niepokój", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "zależność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "ciotka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "tempo", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "odmiana", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wstęp", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "niepodległość", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Putin", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "narracja", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "autorka", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "działka", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "jezioro", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "terapia", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "ograniczenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Amerykanin", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "występ", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "waga", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "Tusk", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "ludność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "parafia", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "Magda", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "drewno", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "dramat", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "obrót", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "dialog", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "panna", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "chory", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Wałęsa", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "teza", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "kolacja", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "rocznica", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "wygląd", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "dzieje", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "przygoda", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "odległość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Wiktor", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "znajomość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Berlin", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wtorek", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "grono", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "weekend", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Włochy", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pochodzenie", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "rano", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "kontrakt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "porażka", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "przyroda", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "liść", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "historyk", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "stosunki", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Dorota", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "skrzydło", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "Brytania", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Ryszard", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Londyn", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "koszula", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "wykonawca", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "Tomek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "serial", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "oświadczenie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "aparat", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "podatnik", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "chodnik", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "bar", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "zasługa", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "przystanek", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "deklaracja", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "trudność", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "złość", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "barwa", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "moda", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "Ania", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "magazyn", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "paliwo", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "świadectwo", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "interwencja", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "motyw", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Wanda", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "urlop", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "akademia", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "marszałek", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "strój", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "przejście", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "reklama", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Mariusz", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "wydanie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "żart", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "rejon", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "kanał", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "odwaga", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "pozór", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "prąd", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dorosły", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "ławka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "dług", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "nienawiść", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "Franciszek", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "potencjał", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "hala", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "pobliże", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "szkolenie", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "komunista", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "Duda", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Julia", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "terytorium", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "torba", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "odniesienie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "śniadanie", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "anioł", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Dawid", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "kodeks", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "wydawnictwo", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "nagranie", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "dno", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "lustro", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "krąg", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "maska", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "pielęgniarka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "edycja", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "talent", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "towarzysz", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "wycieczka", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "troska", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "humor", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "plaża", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "muzyk", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "instrument", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "strażnik", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "mit", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "album", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "VAT", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "przeciwieństwo", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "rana", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "deska", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "przyjaźń", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "przedsięwzięcie", + "metadata": { + "type": "noun", + "score": 3 + } + }, + { + "word": "boisko", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "lot", + "metadata": { + "type": "noun", + "score": 6 + } + }, + { + "word": "szklanka", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "parking", + "metadata": { + "type": "noun", + "score": 9 + } + }, + { + "word": "aspekt", + "metadata": { + "type": "noun", + "score": 4 + } + }, + { + "word": "przychód", + "metadata": { + "type": "noun", + "score": 2 + } + }, + { + "word": "legenda", + "metadata": { + "type": "noun", + "score": 5 + } + }, + { + "word": "trybunał", + "metadata": { + "type": "noun", + "score": 7 + } + }, + { + "word": "półka", + "metadata": { + "type": "noun", + "score": 8 + } + }, + { + "word": "Lwów", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "Hiszpania", + "metadata": { + "type": "noun", + "score": 10 + } + }, + { + "word": "leczenie", + "metadata": { + "type": "noun", + "score": 4 + } + } +] \ No newline at end of file diff --git a/resources/example_dict.json b/resources/example_dict.json new file mode 100644 index 0000000..81beb7a --- /dev/null +++ b/resources/example_dict.json @@ -0,0 +1,12 @@ +[ + {"word": "hello", "metadata": {"type": "greeting", "language": "english"}}, + {"word": "world", "metadata": {"type": "noun", "language": "english"}}, + {"word": "rust", "metadata": {"type": "programming_language", "paradigm": "systems"}}, + {"word": "programming", "metadata": {"type": "verb", "context": "computing"}}, + {"word": "database", "metadata": {"type": "noun", "context": "data_storage"}}, + {"word": "sqlite", "metadata": {"type": "database_engine", "features": ["embedded", "sql"]}}, + {"word": "json", "metadata": {"type": "data_format", "standard": "RFC 8259"}}, + {"word": "import", "metadata": {"type": "verb", "context": "data_operations"}}, + {"word": "dictionary", "metadata": {"type": "noun", "context": "reference"}}, + {"word": "example", "metadata": {"type": "noun", "usage": "demonstration"}} +] \ No newline at end of file