Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ CREATE TABLE status_public.level_requirements (
);

COMMENT ON TABLE status_public.level_requirements IS 'Requirements to achieve a level';
COMMENT ON COLUMN status_public.level_requirements.id IS 'Unique identifier for this requirement';
COMMENT ON COLUMN status_public.level_requirements.name IS 'Requirement name (e.g. posts_created, logins); matches user_steps.name';
COMMENT ON COLUMN status_public.level_requirements.level IS 'Level this requirement belongs to (references levels.name)';
COMMENT ON COLUMN status_public.level_requirements.required_count IS 'Number of steps needed to satisfy this requirement (default 1)';
COMMENT ON COLUMN status_public.level_requirements.priority IS 'Display/evaluation order; lower numbers are checked first (default 100)';

CREATE INDEX ON status_public.level_requirements (name, level, priority);
GRANT SELECT ON TABLE status_public.levels TO authenticated;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CREATE TABLE status_public.levels (
);

COMMENT ON TABLE status_public.levels IS 'Levels for achievement';
COMMENT ON COLUMN status_public.levels.name IS 'Unique level name used as the primary key (e.g. bronze, silver, gold)';

GRANT SELECT ON TABLE status_public.levels TO public;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ CREATE TABLE status_public.user_achievements (
);

COMMENT ON TABLE status_public.user_achievements IS 'This table represents the users progress for particular level requirements, tallying the total count. This table is updated via triggers and should not be updated maually.';
COMMENT ON COLUMN status_public.user_achievements.id IS 'Unique identifier for this achievement progress record';
COMMENT ON COLUMN status_public.user_achievements.user_id IS 'User whose progress is being tracked';
COMMENT ON COLUMN status_public.user_achievements.name IS 'Name of the level requirement this progress relates to';
COMMENT ON COLUMN status_public.user_achievements.count IS 'Accumulated count toward the requirement (updated by triggers)';
COMMENT ON COLUMN status_public.user_achievements.created_at IS 'Timestamp when this progress record was first created';

CREATE INDEX ON status_public.user_achievements (user_id, name);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ CREATE TABLE status_public.user_steps (
);

COMMENT ON TABLE status_public.user_steps IS 'The user achieving a requirement for a level. Log table that has every single step ever taken.';
COMMENT ON COLUMN status_public.user_steps.id IS 'Unique identifier for this step record';
COMMENT ON COLUMN status_public.user_steps.user_id IS 'User who performed this step';
COMMENT ON COLUMN status_public.user_steps.name IS 'Name of the level requirement this step counts toward';
COMMENT ON COLUMN status_public.user_steps.count IS 'Number of units this step contributes (default 1)';
COMMENT ON COLUMN status_public.user_steps.created_at IS 'Timestamp when this step was recorded';

CREATE INDEX ON status_public.user_steps (user_id, name);

COMMIT;
4 changes: 2 additions & 2 deletions packages/achievements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/achievements",
"version": "0.17.0",
"version": "0.15.5",
"description": "Achievement system for tracking user progress and milestones",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -25,7 +25,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
18 changes: 17 additions & 1 deletion packages/achievements/sql/pgpm-achievements--0.15.3.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ CREATE TABLE status_public.user_steps (
);

COMMENT ON TABLE status_public.user_steps IS 'The user achieving a requirement for a level. Log table that has every single step ever taken.';
COMMENT ON COLUMN status_public.user_steps.id IS 'Unique identifier for this step record';
COMMENT ON COLUMN status_public.user_steps.user_id IS 'User who performed this step';
COMMENT ON COLUMN status_public.user_steps.name IS 'Name of the level requirement this step counts toward';
COMMENT ON COLUMN status_public.user_steps.count IS 'Number of units this step contributes (default 1)';
COMMENT ON COLUMN status_public.user_steps.created_at IS 'Timestamp when this step was recorded';

CREATE INDEX ON status_public.user_steps (user_id, name);

Expand Down Expand Up @@ -124,6 +129,11 @@ CREATE TABLE status_public.user_achievements (
);

COMMENT ON TABLE status_public.user_achievements IS 'This table represents the users progress for particular level requirements, tallying the total count. This table is updated via triggers and should not be updated maually.';
COMMENT ON COLUMN status_public.user_achievements.id IS 'Unique identifier for this achievement progress record';
COMMENT ON COLUMN status_public.user_achievements.user_id IS 'User whose progress is being tracked';
COMMENT ON COLUMN status_public.user_achievements.name IS 'Name of the level requirement this progress relates to';
COMMENT ON COLUMN status_public.user_achievements.count IS 'Accumulated count toward the requirement (updated by triggers)';
COMMENT ON COLUMN status_public.user_achievements.created_at IS 'Timestamp when this progress record was first created';

CREATE INDEX ON status_public.user_achievements (user_id, name);

Expand All @@ -145,6 +155,7 @@ CREATE TABLE status_public.levels (
);

COMMENT ON TABLE status_public.levels IS 'Levels for achievement';
COMMENT ON COLUMN status_public.levels.name IS 'Unique level name used as the primary key (e.g. bronze, silver, gold)';

GRANT SELECT ON status_public.levels TO PUBLIC;

Expand All @@ -158,6 +169,11 @@ CREATE TABLE status_public.level_requirements (
);

COMMENT ON TABLE status_public.level_requirements IS 'Requirements to achieve a level';
COMMENT ON COLUMN status_public.level_requirements.id IS 'Unique identifier for this requirement';
COMMENT ON COLUMN status_public.level_requirements.name IS 'Requirement name (e.g. posts_created, logins); matches user_steps.name';
COMMENT ON COLUMN status_public.level_requirements.level IS 'Level this requirement belongs to (references levels.name)';
COMMENT ON COLUMN status_public.level_requirements.required_count IS 'Number of steps needed to satisfy this requirement (default 1)';
COMMENT ON COLUMN status_public.level_requirements.priority IS 'Display/evaluation order; lower numbers are checked first (default 100)';

CREATE INDEX ON status_public.level_requirements (name, level, priority);

Expand Down Expand Up @@ -261,4 +277,4 @@ CREATE TRIGGER update_achievements_tg
AFTER INSERT
ON status_public.user_steps
FOR EACH ROW
EXECUTE PROCEDURE status_private.tg_update_achievements_tg();
EXECUTE PROCEDURE status_private.tg_update_achievements_tg();
4 changes: 2 additions & 2 deletions packages/base32/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/base32",
"version": "0.17.0",
"version": "0.15.5",
"description": "Base32 encoding and decoding functions for PostgreSQL",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -24,7 +24,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,12 @@ CREATE TABLE app_jobs.job_queues (
locked_at timestamptz,
locked_by text
);

COMMENT ON TABLE app_jobs.job_queues IS 'Queue metadata: tracks job counts and locking state for each named queue';
COMMENT ON COLUMN app_jobs.job_queues.queue_name IS 'Unique name identifying this queue';
COMMENT ON COLUMN app_jobs.job_queues.job_count IS 'Number of pending jobs in this queue';
COMMENT ON COLUMN app_jobs.job_queues.locked_at IS 'Timestamp when this queue was locked for batch processing';
COMMENT ON COLUMN app_jobs.job_queues.locked_by IS 'Identifier of the worker that currently holds the queue lock';

COMMIT;

Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,21 @@ CREATE TABLE app_jobs.jobs (
CHECK (length(locked_by) > 3),
UNIQUE (key)
);

COMMENT ON TABLE app_jobs.jobs IS 'Background job queue with database scoping: each row is a pending or in-progress task for a specific database';
COMMENT ON COLUMN app_jobs.jobs.id IS 'Auto-incrementing job identifier';
COMMENT ON COLUMN app_jobs.jobs.database_id IS 'Database this job belongs to, for multi-tenant job isolation';
COMMENT ON COLUMN app_jobs.jobs.queue_name IS 'Name of the queue this job belongs to; used for worker routing and concurrency control';
COMMENT ON COLUMN app_jobs.jobs.task_identifier IS 'Identifier for the task type (maps to a worker handler function)';
COMMENT ON COLUMN app_jobs.jobs.payload IS 'JSON payload of arguments passed to the task handler';
COMMENT ON COLUMN app_jobs.jobs.priority IS 'Execution priority; lower numbers run first (default 0)';
COMMENT ON COLUMN app_jobs.jobs.run_at IS 'Earliest time this job should be executed; used for delayed/scheduled execution';
COMMENT ON COLUMN app_jobs.jobs.attempts IS 'Number of times this job has been attempted so far';
COMMENT ON COLUMN app_jobs.jobs.max_attempts IS 'Maximum retry attempts before the job is considered permanently failed';
COMMENT ON COLUMN app_jobs.jobs.key IS 'Optional unique deduplication key; prevents duplicate jobs with the same key';
COMMENT ON COLUMN app_jobs.jobs.last_error IS 'Error message from the most recent failed attempt';
COMMENT ON COLUMN app_jobs.jobs.locked_at IS 'Timestamp when a worker locked this job for processing';
COMMENT ON COLUMN app_jobs.jobs.locked_by IS 'Identifier of the worker that currently holds the lock';

COMMIT;

Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,21 @@ CREATE TABLE app_jobs.scheduled_jobs (
CHECK (length(locked_by) > 3),
UNIQUE (key)
);

COMMENT ON TABLE app_jobs.scheduled_jobs IS 'Recurring/cron-style job definitions with database scoping: each row spawns jobs on a schedule for a specific database';
COMMENT ON COLUMN app_jobs.scheduled_jobs.id IS 'Auto-incrementing scheduled job identifier';
COMMENT ON COLUMN app_jobs.scheduled_jobs.database_id IS 'Database this scheduled job belongs to, for multi-tenant isolation';
COMMENT ON COLUMN app_jobs.scheduled_jobs.queue_name IS 'Name of the queue spawned jobs are placed into';
COMMENT ON COLUMN app_jobs.scheduled_jobs.task_identifier IS 'Task type identifier for spawned jobs';
COMMENT ON COLUMN app_jobs.scheduled_jobs.payload IS 'JSON payload passed to each spawned job';
COMMENT ON COLUMN app_jobs.scheduled_jobs.priority IS 'Priority assigned to spawned jobs (lower = higher priority)';
COMMENT ON COLUMN app_jobs.scheduled_jobs.max_attempts IS 'Max retry attempts for spawned jobs';
COMMENT ON COLUMN app_jobs.scheduled_jobs.key IS 'Optional unique deduplication key';
COMMENT ON COLUMN app_jobs.scheduled_jobs.locked_at IS 'Timestamp when the scheduler locked this record for processing';
COMMENT ON COLUMN app_jobs.scheduled_jobs.locked_by IS 'Identifier of the scheduler worker holding the lock';
COMMENT ON COLUMN app_jobs.scheduled_jobs.schedule_info IS 'JSON schedule configuration (e.g. cron expression, interval)';
COMMENT ON COLUMN app_jobs.scheduled_jobs.last_scheduled IS 'Timestamp when a job was last spawned from this schedule';
COMMENT ON COLUMN app_jobs.scheduled_jobs.last_scheduled_id IS 'ID of the last job spawned from this schedule';

COMMIT;

4 changes: 2 additions & 2 deletions packages/database-jobs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/database-jobs",
"version": "0.17.0",
"version": "0.15.5",
"description": "Database-specific job handling and queue management",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -21,7 +21,7 @@
"test:watch": "jest --watch"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"dependencies": {
"@pgpm/verify": "workspace:*"
Expand Down
38 changes: 37 additions & 1 deletion packages/database-jobs/sql/pgpm-database-jobs--0.15.3.sql
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ CREATE TABLE app_jobs.scheduled_jobs (
UNIQUE (key)
);

COMMENT ON TABLE app_jobs.scheduled_jobs IS 'Recurring/cron-style job definitions with database scoping: each row spawns jobs on a schedule for a specific database';
COMMENT ON COLUMN app_jobs.scheduled_jobs.id IS 'Auto-incrementing scheduled job identifier';
COMMENT ON COLUMN app_jobs.scheduled_jobs.database_id IS 'Database this scheduled job belongs to, for multi-tenant isolation';
COMMENT ON COLUMN app_jobs.scheduled_jobs.queue_name IS 'Name of the queue spawned jobs are placed into';
COMMENT ON COLUMN app_jobs.scheduled_jobs.task_identifier IS 'Task type identifier for spawned jobs';
COMMENT ON COLUMN app_jobs.scheduled_jobs.payload IS 'JSON payload passed to each spawned job';
COMMENT ON COLUMN app_jobs.scheduled_jobs.priority IS 'Priority assigned to spawned jobs (lower = higher priority)';
COMMENT ON COLUMN app_jobs.scheduled_jobs.max_attempts IS 'Max retry attempts for spawned jobs';
COMMENT ON COLUMN app_jobs.scheduled_jobs.key IS 'Optional unique deduplication key';
COMMENT ON COLUMN app_jobs.scheduled_jobs.locked_at IS 'Timestamp when the scheduler locked this record for processing';
COMMENT ON COLUMN app_jobs.scheduled_jobs.locked_by IS 'Identifier of the scheduler worker holding the lock';
COMMENT ON COLUMN app_jobs.scheduled_jobs.schedule_info IS 'JSON schedule configuration (e.g. cron expression, interval)';
COMMENT ON COLUMN app_jobs.scheduled_jobs.last_scheduled IS 'Timestamp when a job was last spawned from this schedule';
COMMENT ON COLUMN app_jobs.scheduled_jobs.last_scheduled_id IS 'ID of the last job spawned from this schedule';

CREATE FUNCTION app_jobs.do_notify() RETURNS trigger AS $EOFCODE$
BEGIN
PERFORM
Expand Down Expand Up @@ -176,6 +191,21 @@ CREATE TABLE app_jobs.jobs (
UNIQUE (key)
);

COMMENT ON TABLE app_jobs.jobs IS 'Background job queue with database scoping: each row is a pending or in-progress task for a specific database';
COMMENT ON COLUMN app_jobs.jobs.id IS 'Auto-incrementing job identifier';
COMMENT ON COLUMN app_jobs.jobs.database_id IS 'Database this job belongs to, for multi-tenant job isolation';
COMMENT ON COLUMN app_jobs.jobs.queue_name IS 'Name of the queue this job belongs to; used for worker routing and concurrency control';
COMMENT ON COLUMN app_jobs.jobs.task_identifier IS 'Identifier for the task type (maps to a worker handler function)';
COMMENT ON COLUMN app_jobs.jobs.payload IS 'JSON payload of arguments passed to the task handler';
COMMENT ON COLUMN app_jobs.jobs.priority IS 'Execution priority; lower numbers run first (default 0)';
COMMENT ON COLUMN app_jobs.jobs.run_at IS 'Earliest time this job should be executed; used for delayed/scheduled execution';
COMMENT ON COLUMN app_jobs.jobs.attempts IS 'Number of times this job has been attempted so far';
COMMENT ON COLUMN app_jobs.jobs.max_attempts IS 'Maximum retry attempts before the job is considered permanently failed';
COMMENT ON COLUMN app_jobs.jobs.key IS 'Optional unique deduplication key; prevents duplicate jobs with the same key';
COMMENT ON COLUMN app_jobs.jobs.last_error IS 'Error message from the most recent failed attempt';
COMMENT ON COLUMN app_jobs.jobs.locked_at IS 'Timestamp when a worker locked this job for processing';
COMMENT ON COLUMN app_jobs.jobs.locked_by IS 'Identifier of the worker that currently holds the lock';

ALTER TABLE app_jobs.jobs
ADD COLUMN created_at timestamptz;

Expand Down Expand Up @@ -275,6 +305,12 @@ CREATE TABLE app_jobs.job_queues (
locked_by text
);

COMMENT ON TABLE app_jobs.job_queues IS 'Queue metadata: tracks job counts and locking state for each named queue';
COMMENT ON COLUMN app_jobs.job_queues.queue_name IS 'Unique name identifying this queue';
COMMENT ON COLUMN app_jobs.job_queues.job_count IS 'Number of pending jobs in this queue';
COMMENT ON COLUMN app_jobs.job_queues.locked_at IS 'Timestamp when this queue was locked for batch processing';
COMMENT ON COLUMN app_jobs.job_queues.locked_by IS 'Identifier of the worker that currently holds the queue lock';

CREATE INDEX job_queues_locked_by_idx ON app_jobs.job_queues (locked_by);

GRANT SELECT, INSERT, UPDATE, DELETE ON app_jobs.job_queues TO administrator;
Expand Down Expand Up @@ -766,4 +802,4 @@ BEGIN

RETURN v_job;
END;
$EOFCODE$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
$EOFCODE$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
4 changes: 2 additions & 2 deletions packages/defaults/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/defaults",
"version": "0.17.0",
"version": "0.15.5",
"description": "Security defaults and baseline configurations",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -24,7 +24,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,11 @@ CREATE TABLE secrets_schema.secrets_table (
UNIQUE(secrets_owned_field, name)
);

COMMENT ON TABLE secrets_schema.secrets_table IS 'Encrypted key-value secret storage: stores secrets as either raw bytea or encrypted text, scoped to an owning entity';
COMMENT ON COLUMN secrets_schema.secrets_table.id IS 'Unique identifier for this secret';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_owned_field IS 'UUID of the owning entity (e.g. user, organization); combined with name forms a unique key';
COMMENT ON COLUMN secrets_schema.secrets_table.name IS 'Name/key for this secret within its owner scope';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_value_field IS 'Raw binary secret value (mutually exclusive with secrets_enc_field)';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_enc_field IS 'Encrypted text secret value (mutually exclusive with secrets_value_field)';

COMMIT;
4 changes: 2 additions & 2 deletions packages/encrypted-secrets-table/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/encrypted-secrets-table",
"version": "0.17.0",
"version": "0.15.5",
"description": "Table-based encrypted secrets storage and retrieval",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -24,7 +24,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ CREATE TABLE secrets_schema.secrets_table (
UNIQUE (secrets_owned_field, name)
);

COMMENT ON TABLE secrets_schema.secrets_table IS 'Encrypted key-value secret storage: stores secrets as either raw bytea or encrypted text, scoped to an owning entity';
COMMENT ON COLUMN secrets_schema.secrets_table.id IS 'Unique identifier for this secret';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_owned_field IS 'UUID of the owning entity (e.g. user, organization); combined with name forms a unique key';
COMMENT ON COLUMN secrets_schema.secrets_table.name IS 'Name/key for this secret within its owner scope';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_value_field IS 'Raw binary secret value (mutually exclusive with secrets_enc_field)';
COMMENT ON COLUMN secrets_schema.secrets_table.secrets_enc_field IS 'Encrypted text secret value (mutually exclusive with secrets_value_field)';

CREATE FUNCTION secrets_schema.tg_hash_secrets() RETURNS trigger AS $EOFCODE$
BEGIN
IF (NEW.secrets_enc_field = 'crypt') THEN
Expand All @@ -34,4 +41,4 @@ CREATE TRIGGER hash_secrets_insert
BEFORE INSERT
ON secrets_schema.secrets_table
FOR EACH ROW
EXECUTE PROCEDURE secrets_schema.tg_hash_secrets();
EXECUTE PROCEDURE secrets_schema.tg_hash_secrets();
4 changes: 2 additions & 2 deletions packages/encrypted-secrets/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/encrypted-secrets",
"version": "0.17.0",
"version": "0.15.5",
"description": "Encrypted secrets management for PostgreSQL",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -25,7 +25,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions packages/faker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/faker",
"version": "0.17.0",
"version": "0.15.5",
"description": "Fake data generation utilities for testing and development",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -25,7 +25,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions packages/geotypes/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/geotypes",
"version": "0.17.0",
"version": "0.15.5",
"description": "Geographic data types and spatial functions for PostgreSQL",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand All @@ -25,7 +25,7 @@
"@pgpm/verify": "workspace:*"
},
"devDependencies": {
"pgpm": "^4.2.1"
"pgpm": "^4.2.3"
},
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/inflection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ SELECT slug FROM blog_posts;

## Integration Examples

### With @pgpm/metaschema-schema
### With @pgpm/db-meta-schema

Use inflection for schema introspection and code generation:

Expand Down
Loading