@wxn0brp/db-core 0.12.6 → 0.12.8-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,4 +28,6 @@ export declare abstract class ActionsBase implements ActionsBaseInterface {
28
28
  createIndex(config: VQueryT.CreateIndex): Promise<void>;
29
29
  updateOneOrAdd(config: VQueryT.UpdateOneOrAdd): Promise<VQueryT.UpdateOneOrAddResult<DataInternal>>;
30
30
  toggleOne(config: VQueryT.ToggleOne): Promise<VQueryT.ToggleOneResult<DataInternal>>;
31
+ count(config: VQueryT.Count): Promise<number>;
32
+ bulkAdd(config: VQueryT.BulkAdd): Promise<DataInternal[]>;
31
33
  }
@@ -50,4 +50,21 @@ export class ActionsBase {
50
50
  type: "added",
51
51
  };
52
52
  }
53
+ async count(config) {
54
+ return await this.find(config).then(res => res.length);
55
+ }
56
+ async bulkAdd(config) {
57
+ const results = [];
58
+ for (const item of config.datas) {
59
+ const result = await this.add({
60
+ collection: config.collection,
61
+ data: item,
62
+ id_gen: config.id_gen,
63
+ control: config.control,
64
+ transaction: config.transaction,
65
+ });
66
+ results.push(result);
67
+ }
68
+ return results;
69
+ }
53
70
  }
@@ -23,7 +23,7 @@ export declare abstract class CustomActionsBase extends ActionsBase {
23
23
  /**
24
24
  * Update the first matching entry in the specified database based on search criteria and an updater function or object.
25
25
  */
26
- updateOne(query: VQueryT.Update): Promise<import("../types/data.js").DataInternal>;
26
+ updateOne(query: VQueryT.Update): Promise<import("../types/data.js").DataInternal | null>;
27
27
  /**
28
28
  * Remove entries from the specified database based on search criteria.
29
29
  */
@@ -31,5 +31,5 @@ export declare abstract class CustomActionsBase extends ActionsBase {
31
31
  /**
32
32
  * Remove the first matching entry from the specified database based on search criteria.
33
33
  */
34
- removeOne(query: VQueryT.Remove): Promise<import("../types/data.js").DataInternal>;
34
+ removeOne(query: VQueryT.Remove): Promise<import("../types/data.js").DataInternal | null>;
35
35
  }
@@ -1,6 +1,7 @@
1
1
  import { CustomActionsBase } from "../base/custom.js";
2
2
  import { Collection } from "../helpers/collection.js";
3
3
  import { Data } from "../types/data.js";
4
+ import { VQueryT } from "../types/query.js";
4
5
  import { ValtheraClass } from "./valthera.js";
5
6
  export declare class MemoryAction extends CustomActionsBase {
6
7
  memory: Map<string, any[]>;
@@ -12,6 +13,7 @@ export declare class MemoryAction extends CustomActionsBase {
12
13
  ensureCollection(collection: string): Promise<boolean>;
13
14
  issetCollection(collection: string): Promise<boolean>;
14
15
  removeCollection(collection: string): Promise<boolean>;
16
+ count(config: VQueryT.Count): Promise<number>;
15
17
  }
16
18
  export declare class ValtheraMemory extends ValtheraClass {
17
19
  constructor(...args: any[]);
package/dist/db/memory.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CustomActionsBase } from "../base/custom.js";
2
2
  import { CustomFileCpu } from "../customFileCpu.js";
3
3
  import { forgeTypedValthera } from "../helpers/forge.js";
4
+ import { hasFieldsAdvanced } from "../utils/hasFieldsAdvanced.js";
4
5
  import { ValtheraClass } from "./valthera.js";
5
6
  export class MemoryAction extends CustomActionsBase {
6
7
  memory;
@@ -19,8 +20,7 @@ export class MemoryAction extends CustomActionsBase {
19
20
  this.memory.set(key, data);
20
21
  }
21
22
  async getCollections() {
22
- const collections = Array.from(this.memory.keys());
23
- return collections;
23
+ return Array.from(this.memory.keys());
24
24
  }
25
25
  async ensureCollection(collection) {
26
26
  if (this.memory.has(collection))
@@ -37,6 +37,14 @@ export class MemoryAction extends CustomActionsBase {
37
37
  this.memory.delete(collection);
38
38
  return true;
39
39
  }
40
+ async count(config) {
41
+ const collection = this._readMemory(config.collection);
42
+ let count = 0;
43
+ for (const item of collection)
44
+ if (hasFieldsAdvanced(item, config.search))
45
+ count++;
46
+ return count;
47
+ }
40
48
  }
41
49
  export class ValtheraMemory extends ValtheraClass {
42
50
  constructor(...args) {
@@ -9,11 +9,11 @@ export declare class MultiBackend extends ActionsBase {
9
9
  close(...args: any[]): Promise<void>;
10
10
  add(config: VQueryT.Add): Promise<import("../types/data.js").DataInternal>;
11
11
  find(config: VQueryT.Find): Promise<import("../types/data.js").DataInternal[]>;
12
- findOne(config: VQueryT.FindOne): Promise<import("../types/data.js").DataInternal>;
12
+ findOne(config: VQueryT.FindOne): Promise<import("../types/data.js").DataInternal | null>;
13
13
  update(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal[]>;
14
- updateOne(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal>;
14
+ updateOne(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal | null>;
15
15
  remove(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal[]>;
16
- removeOne(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal>;
16
+ removeOne(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal | null>;
17
17
  ensureCollection(collection: string): Promise<boolean>;
18
18
  issetCollection(collection: string): Promise<boolean>;
19
19
  removeCollection(collection: string): Promise<boolean>;
@@ -17,11 +17,11 @@ export declare class RoutedStorage extends ActionsBase {
17
17
  close(...args: any[]): Promise<void>;
18
18
  add(config: VQueryT.Add): Promise<import("../types/data.js").DataInternal>;
19
19
  find(config: VQueryT.Find): Promise<import("../types/data.js").DataInternal[]>;
20
- findOne(config: VQueryT.FindOne): Promise<import("../types/data.js").DataInternal>;
20
+ findOne(config: VQueryT.FindOne): Promise<import("../types/data.js").DataInternal | null>;
21
21
  update(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal[]>;
22
- updateOne(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal>;
22
+ updateOne(config: VQueryT.Update): Promise<import("../types/data.js").DataInternal | null>;
23
23
  remove(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal[]>;
24
- removeOne(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal>;
24
+ removeOne(config: VQueryT.Remove): Promise<import("../types/data.js").DataInternal | null>;
25
25
  ensureCollection(collection: string): Promise<boolean>;
26
26
  issetCollection(collection: string): Promise<boolean>;
27
27
  removeCollection(collection: string): Promise<boolean>;
@@ -13,14 +13,16 @@ export declare class Transaction {
13
13
  constructor(handle: TransactionHandle, _parent: ValtheraClass);
14
14
  c<T = Data>(name: string): Collection<T>;
15
15
  add<T = Data>(q: VQueryT.Add<T>): Promise<T>;
16
+ bulkAdd<T = Data>(q: VQueryT.BulkAdd<T>): Promise<import("../types/data.js").DataInternal[]>;
16
17
  find<T = Data>(q: VQueryT.Find<T, true>): Promise<T[]>;
17
- findOne<T = Data>(q: VQueryT.FindOne<T>): Promise<T>;
18
+ findOne<T = Data>(q: VQueryT.FindOne<T>): Promise<T | null>;
18
19
  update<T = Data>(q: VQueryT.Update<T>): Promise<T[]>;
19
- updateOne<T = Data>(q: VQueryT.Update<T>): Promise<T>;
20
+ updateOne<T = Data>(q: VQueryT.Update<T>): Promise<T | null>;
20
21
  remove<T = Data>(q: VQueryT.Remove<T>): Promise<T[]>;
21
- removeOne<T = Data>(q: VQueryT.Remove<T>): Promise<T>;
22
+ removeOne<T = Data>(q: VQueryT.Remove<T>): Promise<T | null>;
22
23
  updateOneOrAdd<T = Data>(q: VQueryT.UpdateOneOrAdd<T>): Promise<VQueryT.UpdateOneOrAddResult<T>>;
23
24
  toggleOne<T = Data>(q: VQueryT.ToggleOne<T>): Promise<VQueryT.ToggleOneResult<T>>;
25
+ count<T = Data>(q: VQueryT.Count<T>): Promise<number>;
24
26
  ensureCollection(collection: string): Promise<boolean>;
25
27
  issetCollection(collection: string): Promise<boolean>;
26
28
  getCollections(): Promise<string[]>;
@@ -1,5 +1,5 @@
1
1
  import { Collection } from "../helpers/collection.js";
2
- import { applyAddDefaults, applyFindDefaults, applyFindOneDefaults, applyRemoveDefaults, applyToggleOneDefaults, applyUpdateDefaults, applyUpdateOneOrAddDefaults, } from "../helpers/queryDefaults.js";
2
+ import { applyAddDefaults, applyBulkAddDefaults, applyCountDefaults, applyFindDefaults, applyFindOneDefaults, applyRemoveDefaults, applyToggleOneDefaults, applyUpdateDefaults, applyUpdateOneOrAddDefaults, } from "../helpers/queryDefaults.js";
3
3
  /**
4
4
  * Transaction context. Operations are executed directly through the parent
5
5
  * database with the transaction handle passed to the executor.
@@ -18,6 +18,10 @@ export class Transaction {
18
18
  applyAddDefaults(q);
19
19
  return this._parent.execute("add", q, this.handle);
20
20
  }
21
+ bulkAdd(q) {
22
+ applyBulkAddDefaults(q);
23
+ return this._parent.adapter.bulkAdd(q);
24
+ }
21
25
  find(q) {
22
26
  applyFindDefaults(q);
23
27
  return this._parent.execute("find", q, this.handle);
@@ -50,6 +54,10 @@ export class Transaction {
50
54
  applyToggleOneDefaults(q);
51
55
  return this._parent.execute("toggleOne", q, this.handle);
52
56
  }
57
+ count(q) {
58
+ applyCountDefaults(q);
59
+ return this._parent.adapter.count(q);
60
+ }
53
61
  ensureCollection(collection) {
54
62
  return this._parent.adapter.ensureCollection(collection);
55
63
  }
@@ -51,6 +51,7 @@ export declare class ValtheraClass implements ValtheraCompatible {
51
51
  * Add data to a database.
52
52
  */
53
53
  add<T = Data>(query: VQueryT.Add<T>): Promise<T>;
54
+ bulkAdd<T = Data>(query: VQueryT.BulkAdd<T>): Promise<T[]>;
54
55
  /**
55
56
  * Find data in a database.
56
57
  */
@@ -58,7 +59,7 @@ export declare class ValtheraClass implements ValtheraCompatible {
58
59
  /**
59
60
  * Find one data entry in a database.
60
61
  */
61
- findOne<T = Data>(query: VQueryT.FindOne<T>): Promise<T>;
62
+ findOne<T = Data>(query: VQueryT.FindOne<T>): Promise<T | null>;
62
63
  /**
63
64
  * Update data in a database.
64
65
  */
@@ -66,7 +67,7 @@ export declare class ValtheraClass implements ValtheraCompatible {
66
67
  /**
67
68
  * Update one data entry in a database.
68
69
  */
69
- updateOne<T = Data>(query: VQueryT.Update<T>): Promise<T>;
70
+ updateOne<T = Data>(query: VQueryT.Update<T>): Promise<T | null>;
70
71
  /**
71
72
  * Remove data from a database.
72
73
  */
@@ -74,7 +75,7 @@ export declare class ValtheraClass implements ValtheraCompatible {
74
75
  /**
75
76
  * Remove one data entry from a database.
76
77
  */
77
- removeOne<T = Data>(query: VQueryT.Remove<T>): Promise<T>;
78
+ removeOne<T = Data>(query: VQueryT.Remove<T>): Promise<T | null>;
78
79
  /**
79
80
  * Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
80
81
  */
@@ -91,6 +92,7 @@ export declare class ValtheraClass implements ValtheraCompatible {
91
92
  * Create an index on a collection.
92
93
  */
93
94
  createIndex(collection: string, fields: string[], opts?: IndexOpts): Promise<void>;
95
+ count(query: VQueryT.Count): Promise<number>;
94
96
  /**
95
97
  * @experimental
96
98
  *
@@ -2,7 +2,7 @@ import { VEE } from "@wxn0brp/event-emitter";
2
2
  import { Collection } from "../helpers/collection.js";
3
3
  import { SmartExecutor } from "../helpers/executor.js";
4
4
  import { genId } from "../helpers/gen.js";
5
- import { applyAddDefaults, applyFindDefaults, applyFindOneDefaults, applyRemoveDefaults, applyToggleOneDefaults, applyUpdateDefaults, applyUpdateOneOrAddDefaults, } from "../helpers/queryDefaults.js";
5
+ import { applyAddDefaults, applyCountDefaults, applyBulkAddDefaults, applyFindDefaults, applyFindOneDefaults, applyRemoveDefaults, applyToggleOneDefaults, applyUpdateDefaults, applyUpdateOneOrAddDefaults, } from "../helpers/queryDefaults.js";
6
6
  import { version } from "../version.js";
7
7
  import { Transaction } from "./transaction.js";
8
8
  /**
@@ -138,6 +138,10 @@ export class ValtheraClass {
138
138
  applyAddDefaults(query);
139
139
  return this.execute("add", query);
140
140
  }
141
+ bulkAdd(query) {
142
+ applyBulkAddDefaults(query);
143
+ return this.execute("bulkAdd", query);
144
+ }
141
145
  /**
142
146
  * Find data in a database.
143
147
  */
@@ -215,6 +219,10 @@ export class ValtheraClass {
215
219
  index,
216
220
  });
217
221
  }
222
+ count(query) {
223
+ applyCountDefaults(query);
224
+ return this.execute("count", query);
225
+ }
218
226
  /**
219
227
  * @experimental
220
228
  *
@@ -1,3 +1,4 @@
1
1
  import { ActionsBase } from "../base/actions.js";
2
- import { VQuery } from "../types/query.js";
3
- export declare function addId(query: VQuery, actions: ActionsBase, defaultGen?: boolean): Promise<import("../types/arg.js").Arg<import("../types/data.js").Data>>;
2
+ import { VQuery, VQueryT } from "../types/query.js";
3
+ export declare function addId(query: VQuery, actions: ActionsBase, defaultGen?: boolean): Promise<import("../types/arg.js").Arg<import("../types/data.js").Data> | undefined>;
4
+ export declare function addIdBulk(query: VQueryT.BulkAdd, actions: ActionsBase, defaultGen?: boolean): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { genId } from "./gen.js";
2
2
  export async function addId(query, actions, defaultGen = true) {
3
- const { collection, data } = query;
3
+ const collection = query.collection;
4
+ const data = query.data;
4
5
  const id_gen = query.id_gen ?? defaultGen;
5
6
  const { idKey = "_id", numberId } = actions.adapterOpts;
6
7
  if (!id_gen)
@@ -38,3 +39,49 @@ export async function addId(query, actions, defaultGen = true) {
38
39
  ...txOpts,
39
40
  });
40
41
  }
42
+ export async function addIdBulk(query, actions, defaultGen = true) {
43
+ const collection = query.collection;
44
+ const id_gen = query.id_gen ?? defaultGen;
45
+ const { idKey = "_id", numberId } = actions.adapterOpts;
46
+ if (!id_gen)
47
+ return;
48
+ if (!numberId) {
49
+ for (const data of query.datas) {
50
+ if (!data[idKey])
51
+ data[idKey] = genId();
52
+ }
53
+ return;
54
+ }
55
+ const txOpts = query.transaction
56
+ ? {
57
+ transaction: query.transaction,
58
+ }
59
+ : {};
60
+ const find = (await actions.findOne({
61
+ collection: "__vdb_id",
62
+ search: {
63
+ c: collection,
64
+ },
65
+ ...txOpts,
66
+ }));
67
+ const start = find?.i ?? 0;
68
+ for (let i = 0; i < query.datas.length; i++) {
69
+ const data = query.datas[i];
70
+ if (!data[idKey]) {
71
+ data[idKey] = start + i + 1;
72
+ }
73
+ }
74
+ await actions.updateOneOrAdd({
75
+ collection: "__vdb_id",
76
+ search: {
77
+ c: collection,
78
+ },
79
+ updater: {
80
+ $inc: {
81
+ i: query.datas.length,
82
+ },
83
+ },
84
+ id_gen: false,
85
+ ...txOpts,
86
+ });
87
+ }
@@ -17,6 +17,10 @@ export declare class Collection<D = Data> {
17
17
  add(data: Arg<D>, id_gen?: true): Promise<D & {
18
18
  _id: string;
19
19
  }>;
20
+ bulkAdd(data: Arg<D>[], id_gen: false): Promise<D[]>;
21
+ bulkAdd(data: Arg<D>[], id_gen?: true): Promise<(D & {
22
+ _id: string;
23
+ })[]>;
20
24
  /**
21
25
  * Find data in a database.
22
26
  */
@@ -24,7 +28,11 @@ export declare class Collection<D = Data> {
24
28
  /**
25
29
  * Find one data entry in a database.
26
30
  */
27
- findOne(search?: Search<D>, findOpts?: FindOpts<D>, context?: VContext): Promise<D>;
31
+ findOne(search?: Search<D>, findOpts?: FindOpts<D>, context?: VContext): Promise<D | null>;
32
+ /**
33
+ * Count data entries in a database.
34
+ */
35
+ count(search?: Search<D, false>): Promise<number>;
28
36
  /**
29
37
  * Update data in a database.
30
38
  */
@@ -12,6 +12,13 @@ export class Collection {
12
12
  id_gen,
13
13
  });
14
14
  }
15
+ bulkAdd(data, id_gen) {
16
+ return this.db.bulkAdd({
17
+ collection: this.collection,
18
+ datas: data,
19
+ id_gen,
20
+ });
21
+ }
15
22
  /**
16
23
  * Find data in a database.
17
24
  */
@@ -35,6 +42,15 @@ export class Collection {
35
42
  context,
36
43
  });
37
44
  }
45
+ /**
46
+ * Count data entries in a database.
47
+ */
48
+ count(search = {}) {
49
+ return this.db.count({
50
+ collection: this.collection,
51
+ search,
52
+ });
53
+ }
38
54
  /**
39
55
  * Update data in a database.
40
56
  */
@@ -1,7 +1,7 @@
1
1
  import { Id } from "../types/Id.js";
2
2
  export declare function getIdData(): {
3
3
  usedIds: Map<any, any>;
4
- lastId: Id;
4
+ lastId: Id | undefined;
5
5
  lastTimeStr: string;
6
6
  lastCounter: number;
7
7
  recentIdsTimestamps: number[];
@@ -16,9 +16,9 @@ export type IdData = ReturnType<typeof getIdData>;
16
16
  * @param {number[]} [parts] - an array of lengths of parts of the identifier
17
17
  * @returns {Id} - a new unique identifier
18
18
  */
19
- export declare function genId(parts?: number[], idData?: {
19
+ export declare function genId(parts?: number[] | null, idData?: {
20
20
  usedIds: Map<any, any>;
21
- lastId: Id;
21
+ lastId: Id | undefined;
22
22
  lastTimeStr: string;
23
23
  lastCounter: number;
24
24
  recentIdsTimestamps: number[];
@@ -6,3 +6,5 @@ export declare function applyUpdateDefaults<T>(q: VQueryT.Update<T>): void;
6
6
  export declare function applyRemoveDefaults<T>(q: VQueryT.Remove<T>): void;
7
7
  export declare function applyUpdateOneOrAddDefaults<T>(q: VQueryT.UpdateOneOrAdd<T>): void;
8
8
  export declare function applyToggleOneDefaults<T>(q: VQueryT.ToggleOne<T>): void;
9
+ export declare function applyCountDefaults<T>(q: VQueryT.Count<T>): void;
10
+ export declare function applyBulkAddDefaults<T>(q: VQueryT.BulkAdd<T>): void;
@@ -33,3 +33,12 @@ export function applyToggleOneDefaults(q) {
33
33
  q.context ||= {};
34
34
  q.control ||= {};
35
35
  }
36
+ export function applyCountDefaults(q) {
37
+ q.search ||= {};
38
+ q.control ||= {};
39
+ }
40
+ export function applyBulkAddDefaults(q) {
41
+ q.datas ??= [];
42
+ q.control ||= {};
43
+ q.id_gen ??= true;
44
+ }
@@ -22,6 +22,8 @@ export interface ActionsBaseInterface {
22
22
  removeOne(query: VQueryT.Remove): Promise<DataInternal | null>;
23
23
  updateOneOrAdd(query: VQueryT.UpdateOneOrAdd): Promise<VQueryT.UpdateOneOrAddResult<DataInternal>>;
24
24
  toggleOne(query: VQueryT.ToggleOne): Promise<VQueryT.ToggleOneResult<DataInternal>>;
25
+ count(query: VQueryT.Count): Promise<number>;
26
+ bulkAdd(query: VQueryT.BulkAdd): Promise<DataInternal[]>;
25
27
  beginTransaction(id: Id): Promise<TransactionHandle>;
26
28
  commitTransaction(handle: TransactionHandle): Promise<void>;
27
29
  rollbackTransaction(handle: TransactionHandle): Promise<void>;
@@ -23,6 +23,7 @@ export interface VQuery<T = Data, AllowFn extends boolean = true> {
23
23
  dbFindOpts?: DbFindOpts<T>;
24
24
  findOpts?: FindOpts<T>;
25
25
  data?: Arg<T>;
26
+ datas?: Arg<T>[];
26
27
  id_gen?: boolean;
27
28
  add_arg?: Arg<T>;
28
29
  updater?: Updater<T, AllowFn>;
@@ -40,6 +41,10 @@ export declare namespace VQueryT {
40
41
  data: Arg<T>;
41
42
  id_gen?: boolean;
42
43
  };
44
+ type BulkAdd<T = Data> = QueryBase<T> & {
45
+ datas: Arg<T>[];
46
+ id_gen?: boolean;
47
+ };
43
48
  type Find<T = Data, AllowFn extends boolean = true> = QueryBase<T> & {
44
49
  search?: Search<T, AllowFn>;
45
50
  findOpts?: FindOpts<T>;
@@ -83,4 +88,7 @@ export declare namespace VQueryT {
83
88
  type CreateIndex<T = Data> = QueryBase<T> & {
84
89
  index: IndexDefinition;
85
90
  };
91
+ type Count<T = Data> = QueryBase<T> & {
92
+ search: Search<T, false>;
93
+ };
86
94
  }
@@ -18,4 +18,6 @@ export interface ValtheraCompatible {
18
18
  updateOneOrAdd<T = Data>(query: VQueryT.UpdateOneOrAdd<T>): Promise<VQueryT.UpdateOneOrAddResult<T>>;
19
19
  toggleOne<T = Data>(query: VQueryT.ToggleOne<T>): Promise<VQueryT.ToggleOneResult<T>>;
20
20
  createIndex(collection: string, fields: string[], opts?: IndexOpts): Promise<void>;
21
+ count(query: VQueryT.Count): Promise<number>;
22
+ bulkAdd<T = Data>(query: VQueryT.BulkAdd<T>): Promise<T[]>;
21
23
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.12.6";
1
+ export declare const version = "0.12.8-alpha.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.12.6";
1
+ export const version = "0.12.8-alpha.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/db-core",
3
- "version": "0.12.6",
3
+ "version": "0.12.8-alpha.0",
4
4
  "types": "dist/index.d.ts",
5
5
  "main": "dist/index.js",
6
6
  "author": "wxn0brP",