@ohos-ports/lmdb 2.5.3 → 2.8.5-beta.1

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.
Files changed (124) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +72 -28
  3. package/SECURITY.md +12 -12
  4. package/bin/download-prebuilds.js +15 -0
  5. package/binding.gyp +115 -111
  6. package/build/Release/lmdb.node +0 -0
  7. package/caching.js +212 -156
  8. package/dependencies/lmdb/libraries/liblmdb/COPYRIGHT +20 -20
  9. package/dependencies/lmdb/libraries/liblmdb/Doxyfile +1631 -1631
  10. package/dependencies/lmdb/libraries/liblmdb/LICENSE +47 -47
  11. package/dependencies/lmdb/libraries/liblmdb/Makefile +136 -136
  12. package/dependencies/lmdb/libraries/liblmdb/chacha8.c +183 -183
  13. package/dependencies/lmdb/libraries/liblmdb/chacha8.h +14 -14
  14. package/dependencies/lmdb/libraries/liblmdb/crypto.c +121 -121
  15. package/dependencies/lmdb/libraries/liblmdb/intro.doc +192 -192
  16. package/dependencies/lmdb/libraries/liblmdb/lmdb.h +28 -3
  17. package/dependencies/lmdb/libraries/liblmdb/mdb.c +157 -31
  18. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.1 +74 -74
  19. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.c +106 -106
  20. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.1 +53 -53
  21. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.c +154 -154
  22. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.1 +94 -94
  23. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.c +333 -333
  24. package/dependencies/lmdb/libraries/liblmdb/mdb_load.1 +97 -97
  25. package/dependencies/lmdb/libraries/liblmdb/mdb_load.c +530 -530
  26. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.1 +83 -83
  27. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.c +276 -276
  28. package/dependencies/lmdb/libraries/liblmdb/midl-sparse.c +452 -0
  29. package/dependencies/lmdb/libraries/liblmdb/midl.c +452 -452
  30. package/dependencies/lmdb/libraries/liblmdb/midl.h +208 -208
  31. package/dependencies/lmdb/libraries/liblmdb/module.c +101 -101
  32. package/dependencies/lmdb/libraries/liblmdb/module.h +16 -16
  33. package/dependencies/lmdb/libraries/liblmdb/mtest.c +178 -178
  34. package/dependencies/lmdb/libraries/liblmdb/mtest2.c +124 -124
  35. package/dependencies/lmdb/libraries/liblmdb/mtest3.c +133 -133
  36. package/dependencies/lmdb/libraries/liblmdb/mtest4.c +168 -168
  37. package/dependencies/lmdb/libraries/liblmdb/mtest5.c +135 -135
  38. package/dependencies/lmdb/libraries/liblmdb/mtest6.c +141 -141
  39. package/dependencies/lmdb/libraries/liblmdb/mtest_enc.c +190 -190
  40. package/dependencies/lmdb/libraries/liblmdb/mtest_enc2.c +189 -189
  41. package/dependencies/lmdb/libraries/liblmdb/mtest_remap.c +177 -177
  42. package/dependencies/lmdb/libraries/liblmdb/sample-bdb.txt +73 -73
  43. package/dependencies/lmdb/libraries/liblmdb/sample-mdb.txt +62 -62
  44. package/dependencies/lmdb/libraries/liblmdb/tooltag +27 -27
  45. package/dependencies/lmdb-data-v1/libraries/liblmdb/CHANGES +266 -0
  46. package/dependencies/lmdb-data-v1/libraries/liblmdb/COPYRIGHT +20 -20
  47. package/dependencies/lmdb-data-v1/libraries/liblmdb/Doxyfile +1631 -1631
  48. package/dependencies/lmdb-data-v1/libraries/liblmdb/LICENSE +47 -47
  49. package/dependencies/lmdb-data-v1/libraries/liblmdb/intro.doc +192 -192
  50. package/dependencies/lmdb-data-v1/libraries/liblmdb/lmdb.h +1608 -1653
  51. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb.c +10320 -11359
  52. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.1 +55 -61
  53. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.c +82 -84
  54. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.1 +75 -81
  55. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.c +319 -319
  56. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.1 +84 -84
  57. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.c +496 -492
  58. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.1 +64 -70
  59. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.c +263 -264
  60. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.c +359 -421
  61. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.h +186 -200
  62. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest.c +177 -177
  63. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest2.c +124 -124
  64. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest3.c +133 -133
  65. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest4.c +168 -168
  66. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest5.c +135 -135
  67. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest6.c +141 -141
  68. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-bdb.txt +73 -73
  69. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-mdb.txt +62 -62
  70. package/dependencies/lmdb-data-v1/libraries/liblmdb/tooltag +22 -27
  71. package/dependencies/lz4/LICENSE +11 -11
  72. package/dependencies/lz4/lib/LICENSE +24 -24
  73. package/dependencies/lz4/lib/Makefile +225 -0
  74. package/dependencies/lz4/lib/README.md +169 -137
  75. package/dependencies/lz4/lib/dll/example/Makefile +63 -0
  76. package/dependencies/lz4/lib/dll/example/README.md +69 -69
  77. package/dependencies/lz4/lib/dll/liblz4.def +62 -62
  78. package/dependencies/lz4/lib/liblz4-dll.rc.in +35 -35
  79. package/dependencies/lz4/lib/liblz4.pc.in +14 -14
  80. package/dependencies/lz4/lib/lz4.c +2722 -2495
  81. package/dependencies/lz4/lib/lz4.h +842 -774
  82. package/dependencies/lz4/lib/lz4file.c +311 -0
  83. package/dependencies/lz4/lib/lz4file.h +93 -0
  84. package/dependencies/lz4/lib/lz4frame.c +2078 -1899
  85. package/dependencies/lz4/lib/lz4frame.h +692 -623
  86. package/dependencies/lz4/lib/lz4frame_static.h +47 -47
  87. package/dependencies/lz4/lib/lz4hc.c +1631 -1615
  88. package/dependencies/lz4/lib/lz4hc.h +413 -413
  89. package/dependencies/lz4/lib/xxhash.c +1030 -1030
  90. package/dependencies/lz4/lib/xxhash.h +328 -328
  91. package/dependencies/v8/v8-fast-api-calls-v16.h +790 -790
  92. package/dependencies/v8/v8-fast-api-calls.h +784 -888
  93. package/dist/index.cjs +1050 -584
  94. package/dist/index.cjs.map +1 -1
  95. package/index.d.cts +420 -0
  96. package/index.d.ts +450 -385
  97. package/index.js +38 -37
  98. package/keys.js +116 -102
  99. package/level.js +26 -26
  100. package/native.js +8 -5
  101. package/node-index.js +21 -17
  102. package/open.js +51 -17
  103. package/package.json +55 -21
  104. package/read.js +338 -95
  105. package/src/compression.cpp +12 -9
  106. package/src/cursor.cpp +82 -31
  107. package/src/dbi.cpp +78 -40
  108. package/src/env.cpp +336 -68
  109. package/src/lmdb-js.cpp +64 -64
  110. package/src/lmdb-js.h +83 -49
  111. package/src/misc.cpp +297 -28
  112. package/src/ordered-binary.cpp +46 -46
  113. package/src/txn.cpp +210 -257
  114. package/src/v8-functions.cpp +170 -166
  115. package/src/windows.c +34 -34
  116. package/src/writer.cpp +169 -84
  117. package/util/RangeIterable.js +112 -17
  118. package/util/set-optional-deps.cjs +14 -10
  119. package/util/when.js +8 -8
  120. package/write.js +145 -121
  121. package/dependencies/lmdb-data-v1/libraries/liblmdb/Makefile +0 -118
  122. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.1 +0 -40
  123. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.c +0 -135
  124. package/rollup.config.js +0 -12
package/caching.js CHANGED
@@ -1,156 +1,212 @@
1
- import { WeakLRUCache, clearKeptObjects } from './native.js';
2
- import { FAILED_CONDITION, ABORT } from './write.js';
3
- import { when } from './util/when.js';
4
-
5
- let getLastVersion;
6
- const mapGet = Map.prototype.get;
7
- export const CachingStore = (Store, env) => {
8
- let childTxnChanges
9
- return class extends Store {
10
- constructor(dbName, options) {
11
- super(dbName, options);
12
- if (!env.cacheCommitter) {
13
- env.cacheCommitter = true;
14
- this.on('aftercommit', ({ next, last }) => {
15
- do {
16
- let meta = next.meta;
17
- let store = meta && meta.store;
18
- if (store) {
19
- if (next.flag & FAILED_CONDITION)
20
- store.cache.delete(meta.key); // just delete it from the map
21
- else {
22
- let expirationPriority = meta.valueSize >> 10;
23
- let cache = store.cache;
24
- let entry = mapGet.call(cache, meta.key);
25
- if (entry)
26
- cache.used(entry, expirationPriority + 4); // this will enter it into the LRFU (with a little lower priority than a read)
27
- }
28
- }
29
- } while (next != last && (next = next.next))
30
- });
31
- }
32
- this.db.cachingDb = this;
33
- if (options.cache.clearKeptInterval)
34
- options.cache.clearKeptObjects = clearKeptObjects;
35
- this.cache = new WeakLRUCache(options.cache);
36
- }
37
- get isCaching() {
38
- return true
39
- }
40
- get(id, cacheMode) {
41
- let value = this.cache.getValue(id);
42
- if (value !== undefined)
43
- return value;
44
- value = super.get(id);
45
- if (value && typeof value === 'object' && !cacheMode && typeof id !== 'object') {
46
- let entry = this.cache.setValue(id, value, this.lastSize >> 10);
47
- if (this.useVersions) {
48
- entry.version = getLastVersion();
49
- }
50
- }
51
- return value;
52
- }
53
- getEntry(id, cacheMode) {
54
- let entry = this.cache.get(id);
55
- if (entry)
56
- return entry;
57
- let value = super.get(id);
58
- if (value === undefined)
59
- return;
60
- if (value && typeof value === 'object' && !cacheMode && typeof id !== 'object') {
61
- entry = this.cache.setValue(id, value, this.lastSize >> 10);
62
- } else {
63
- entry = { value };
64
- }
65
- if (this.useVersions) {
66
- entry.version = getLastVersion();
67
- }
68
- return entry;
69
- }
70
- putEntry(id, entry, ifVersion) {
71
- let result = super.put(id, entry.value, entry.version, ifVersion);
72
- if (typeof id === 'object')
73
- return result;
74
- if (result && result.then)
75
- this.cache.setManually(id, entry); // set manually so we can keep it pinned in memory until it is committed
76
- else // sync operation, immediately add to cache
77
- this.cache.set(id, entry);
78
- }
79
- put(id, value, version, ifVersion) {
80
- let result = super.put(id, value, version, ifVersion);
81
- if (typeof id !== 'object') {
82
- if (value && value['\x10binary-data\x02']) {
83
- // don't cache binary data, since it will be decoded on get
84
- this.cache.delete(id);
85
- return result;
86
- }
87
- // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed
88
- let entry = this.cache.setValue(id, value, !result || result.isSync ? 0 : -1);
89
- if (childTxnChanges)
90
- childTxnChanges.add(id);
91
- if (version !== undefined)
92
- entry.version = typeof version === 'object' ? version.version : version;
93
- }
94
- return result;
95
- }
96
- putSync(id, value, version, ifVersion) {
97
- if (id !== 'object') {
98
- // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed
99
- if (value && typeof value === 'object') {
100
- let entry = this.cache.setValue(id, value);
101
- if (childTxnChanges)
102
- childTxnChanges.add(id);
103
- if (version !== undefined) {
104
- entry.version = typeof version === 'object' ? version.version : version;
105
- }
106
- } else // it is possible that a value used to exist here
107
- this.cache.delete(id);
108
- }
109
- return super.putSync(id, value, version, ifVersion);
110
- }
111
- remove(id, ifVersion) {
112
- this.cache.delete(id);
113
- return super.remove(id, ifVersion);
114
- }
115
- removeSync(id, ifVersion) {
116
- this.cache.delete(id);
117
- return super.removeSync(id, ifVersion);
118
- }
119
- clearAsync(callback) {
120
- this.cache.clear();
121
- return super.clearAsync(callback);
122
- }
123
- clearSync() {
124
- this.cache.clear();
125
- super.clearSync();
126
- }
127
- childTransaction(callback) {
128
- return super.childTransaction(() => {
129
- let cache = this.cache;
130
- let previousChanges = childTxnChanges;
131
- try {
132
- childTxnChanges = new Set();
133
- return when(callback(), (result) => {
134
- if (result === ABORT)
135
- return abort();
136
- childTxnChanges = previousChanges;
137
- return result;
138
- }, abort);
139
- } catch(error) {
140
- abort(error);
141
- }
142
- function abort(error) {
143
- // if the transaction was aborted, remove all affected entries from cache
144
- for (let id of childTxnChanges)
145
- cache.delete(id);
146
- childTxnChanges = previousChanges;
147
- if (error)
148
- throw error;
149
- }
150
- });
151
- }
152
- };
153
- };
154
- export function setGetLastVersion(get) {
155
- getLastVersion = get;
156
- }
1
+ import { WeakLRUCache, clearKeptObjects } from './native.js';
2
+ import { FAILED_CONDITION, ABORT, IF_EXISTS } from './write.js';
3
+ import { UNMODIFIED } from './read.js';
4
+ import { when } from './util/when.js';
5
+
6
+ let getLastVersion, getLastTxnId;
7
+ const mapGet = Map.prototype.get;
8
+ export const CachingStore = (Store, env) => {
9
+ let childTxnChanges
10
+ return class LMDBStore extends Store {
11
+ constructor(dbName, options) {
12
+ super(dbName, options);
13
+ if (!env.cacheCommitter) {
14
+ env.cacheCommitter = true;
15
+ this.on('aftercommit', ({ next, last, txnId }) => {
16
+ do {
17
+ let meta = next.meta;
18
+ let store = meta && meta.store;
19
+ if (store) {
20
+ if (next.flag & FAILED_CONDITION)
21
+ store.cache.delete(meta.key); // just delete it from the map
22
+ else {
23
+ let expirationPriority = meta.valueSize >> 10;
24
+ let cache = store.cache;
25
+ let entry = mapGet.call(cache, meta.key);
26
+ if (entry) {
27
+ entry.txnId = txnId;
28
+ cache.used(entry, expirationPriority + 4); // this will enter it into the LRFU (with a little lower priority than a read)
29
+ }
30
+ }
31
+ }
32
+ } while (next != last && (next = next.next))
33
+ });
34
+ }
35
+ this.db.cachingDb = this;
36
+ if (options.cache.clearKeptInterval)
37
+ options.cache.clearKeptObjects = clearKeptObjects;
38
+ this.cache = new WeakLRUCache(options.cache);
39
+ if (options.cache.validated)
40
+ this.cache.validated = true;
41
+ }
42
+ get isCaching() {
43
+ return true
44
+ }
45
+ get(id, options) {
46
+ let value;
47
+ if (this.cache.validated) {
48
+ let entry = this.cache.get(id);
49
+ if (entry) {
50
+ let cachedValue = entry.value;
51
+ if (entry.txnId != null) {
52
+ value = super.get(id, { ifNotTxnId: entry.txnId, transaction: options && options.transaction });
53
+ if (value === UNMODIFIED)
54
+ return cachedValue;
55
+ } else // with no txn id we do not validate; this is the state of a cached value after a write before it transacts
56
+ return cachedValue;
57
+ } else
58
+ value = super.get(id, options);
59
+ } else if (options && options.transaction) {
60
+ return super.get(id, options);
61
+ } else {
62
+ value = this.cache.getValue(id);
63
+ if (value !== undefined) {
64
+ return value;
65
+ }
66
+ value = super.get(id);
67
+ }
68
+ if (value && typeof value === 'object' && !options && typeof id !== 'object') {
69
+ let entry = this.cache.setValue(id, value, this.lastSize >> 10);
70
+ if (this.useVersions) {
71
+ entry.version = getLastVersion();
72
+ }
73
+ if (this.cache.validated)
74
+ entry.txnId = getLastTxnId();
75
+ }
76
+ return value;
77
+ }
78
+ getEntry(id, options) {
79
+ let entry, value;
80
+ if (this.cache.validated) {
81
+ entry = this.cache.get(id);
82
+ if (entry) {
83
+ if (entry.txnId != null) {
84
+ value = super.get(id, { ifNotTxnId: entry.txnId, transaction: options && options.transaction });
85
+ if (value === UNMODIFIED)
86
+ return entry;
87
+ } else // with no txn id we do not validate; this is the state of a cached value after a write before it transacts
88
+ return entry;
89
+ } else
90
+ value = super.get(id, options);
91
+ } else if (options && options.transaction) {
92
+ return super.getEntry(id, options);
93
+ } else {
94
+ entry = this.cache.get(id);
95
+ if (entry !== undefined) {
96
+ return entry;
97
+ }
98
+ value = super.get(id);
99
+ }
100
+ if (value === undefined)
101
+ return;
102
+ if (value && typeof value === 'object' && !options && typeof id !== 'object') {
103
+ entry = this.cache.setValue(id, value, this.lastSize >> 10);
104
+ } else
105
+ entry = { value };
106
+ if (this.useVersions)
107
+ entry.version = getLastVersion();
108
+ if (this.cache.validated)
109
+ entry.txnId = getLastTxnId();
110
+ return entry;
111
+ }
112
+ putEntry(id, entry, ifVersion) {
113
+ let result = super.put(id, entry.value, entry.version, ifVersion);
114
+ if (typeof id === 'object')
115
+ return result;
116
+ if (result && result.then)
117
+ this.cache.setManually(id, entry); // set manually so we can keep it pinned in memory until it is committed
118
+ else // sync operation, immediately add to cache
119
+ this.cache.set(id, entry);
120
+ }
121
+ put(id, value, version, ifVersion) {
122
+ let result = super.put(id, value, version, ifVersion);
123
+ if (typeof id !== 'object') {
124
+ if (value && value['\x10binary-data\x02']) {
125
+ // don't cache binary data, since it will be decoded on get
126
+ this.cache.delete(id);
127
+ return result;
128
+ }
129
+ // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed
130
+ let entry = this.cache.setValue(id, value, !result || result.isSync ? 0 : -1);
131
+ if (childTxnChanges)
132
+ childTxnChanges.add(id);
133
+ if (version !== undefined)
134
+ entry.version = typeof version === 'object' ? version.version : version;
135
+ }
136
+ return result;
137
+ }
138
+ putSync(id, value, version, ifVersion) {
139
+ if (id !== 'object') {
140
+ // sync operation, immediately add to cache, otherwise keep it pinned in memory until it is committed
141
+ if (value && typeof value === 'object') {
142
+ let entry = this.cache.setValue(id, value);
143
+ if (childTxnChanges)
144
+ childTxnChanges.add(id);
145
+ if (version !== undefined) {
146
+ entry.version = typeof version === 'object' ? version.version : version;
147
+ }
148
+ } else // it is possible that a value used to exist here
149
+ this.cache.delete(id);
150
+ }
151
+ return super.putSync(id, value, version, ifVersion);
152
+ }
153
+ remove(id, ifVersion) {
154
+ this.cache.delete(id);
155
+ return super.remove(id, ifVersion);
156
+ }
157
+ removeSync(id, ifVersion) {
158
+ this.cache.delete(id);
159
+ return super.removeSync(id, ifVersion);
160
+ }
161
+ clearAsync(callback) {
162
+ this.cache.clear();
163
+ return super.clearAsync(callback);
164
+ }
165
+ clearSync() {
166
+ this.cache.clear();
167
+ super.clearSync();
168
+ }
169
+ childTransaction(callback) {
170
+ return super.childTransaction(() => {
171
+ let cache = this.cache;
172
+ let previousChanges = childTxnChanges;
173
+ try {
174
+ childTxnChanges = new Set();
175
+ return when(callback(), (result) => {
176
+ if (result === ABORT)
177
+ return abort();
178
+ childTxnChanges = previousChanges;
179
+ return result;
180
+ }, abort);
181
+ } catch(error) {
182
+ abort(error);
183
+ }
184
+ function abort(error) {
185
+ // if the transaction was aborted, remove all affected entries from cache
186
+ for (let id of childTxnChanges)
187
+ cache.delete(id);
188
+ childTxnChanges = previousChanges;
189
+ if (error)
190
+ throw error;
191
+ else
192
+ return ABORT;
193
+ }
194
+ });
195
+ }
196
+ doesExist(key, versionOrValue) {
197
+ let entry = this.cache.get(key);
198
+ if (entry) {
199
+ if (versionOrValue == null) {
200
+ return versionOrValue !== null;
201
+ } else if (this.useVersions) {
202
+ return versionOrValue === IF_EXISTS || entry.version === versionOrValue;
203
+ }
204
+ }
205
+ return super.doesExist(key, versionOrValue);
206
+ }
207
+ };
208
+ };
209
+ export function setGetLastVersion(get, getTxnId) {
210
+ getLastVersion = get;
211
+ getLastTxnId = getTxnId;
212
+ }
@@ -1,20 +1,20 @@
1
- Copyright 2011-2021 Howard Chu, Symas Corp.
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted only as authorized by the OpenLDAP
6
- Public License.
7
-
8
- A copy of this license is available in the file LICENSE in the
9
- top-level directory of the distribution or, alternatively, at
10
- <http://www.OpenLDAP.org/license.html>.
11
-
12
- OpenLDAP is a registered trademark of the OpenLDAP Foundation.
13
-
14
- Individual files and/or contributed packages may be copyright by
15
- other parties and/or subject to additional restrictions.
16
-
17
- This work also contains materials derived from public sources.
18
-
19
- Additional information about OpenLDAP can be obtained at
20
- <http://www.openldap.org/>.
1
+ Copyright 2011-2021 Howard Chu, Symas Corp.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted only as authorized by the OpenLDAP
6
+ Public License.
7
+
8
+ A copy of this license is available in the file LICENSE in the
9
+ top-level directory of the distribution or, alternatively, at
10
+ <http://www.OpenLDAP.org/license.html>.
11
+
12
+ OpenLDAP is a registered trademark of the OpenLDAP Foundation.
13
+
14
+ Individual files and/or contributed packages may be copyright by
15
+ other parties and/or subject to additional restrictions.
16
+
17
+ This work also contains materials derived from public sources.
18
+
19
+ Additional information about OpenLDAP can be obtained at
20
+ <http://www.openldap.org/>.