Permalink
Browse files

Remove JS SDK, examples, and tools (#3293)

  • Loading branch information...
kalman committed Mar 27, 2017
1 parent 44dd79d commit 3c764c1eb5178652d116cb05f8f325ba845c39e3
Showing with 24 additions and 53,291 deletions.
  1. +1 −5 CONTRIBUTING.md
  2. +0 −5 doc/index.md
  3. +21 −6 doc/intro.md
  4. +0 −193 doc/js-tour.md
  5. +1 −1 go/constants/version.go
  6. +1 −3 go/spec/spec_test.go
  7. +0 −3 go/types/blob_test.go
  8. +0 −1 go/types/xp_test.go
  9. +0 −3 js/noms/.babelrc
  10. +0 −7 js/noms/.eslintrc.js
  11. +0 −20 js/noms/.flowconfig
  12. +0 −6 js/noms/.gitignore
  13. +0 −7 js/noms/.npmignore
  14. +0 −17 js/noms/README.md
  15. +0 −17 js/noms/build/make-index-html.js
  16. +0 −61 js/noms/package.json
  17. +0 −100 js/noms/src/absolute-path-test.js
  18. +0 −109 js/noms/src/absolute-path.js
  19. +0 −37 js/noms/src/assert-test.js
  20. +0 −374 js/noms/src/assert-type-test.js
  21. +0 −140 js/noms/src/assert-type.js
  22. +0 −21 js/noms/src/assert.js
  23. +0 −17 js/noms/src/async-iterator.js
  24. +0 −66 js/noms/src/base32-test.js
  25. +0 −105 js/noms/src/base32.js
  26. +0 −105 js/noms/src/base32.js2
  27. +0 −50 js/noms/src/batch-store.js
  28. +0 −33 js/noms/src/binary-noms-reader.js
  29. +0 −45 js/noms/src/binary-noms-writer.js
  30. +0 −177 js/noms/src/binary-rw.js
  31. +0 −28 js/noms/src/binary-search.js
  32. +0 −277 js/noms/src/blob-test.js
  33. +0 −206 js/noms/src/blob.js
  34. +0 −105 js/noms/src/browser/bytes.js
  35. +0 −107 js/noms/src/browser/fetch.js
  36. +0 −114 js/noms/src/browser/put-cache.js
  37. +0 −193 js/noms/src/browser/utf8.js
  38. +0 −85 js/noms/src/buzhash-test.js
  39. +0 −112 js/noms/src/buzhash.js
  40. +0 −204 js/noms/src/bytes-test.js
  41. +0 −22 js/noms/src/bytes-uint32.js
  42. +0 −94 js/noms/src/bytes.js
  43. +0 −107 js/noms/src/chunk-serializer-test.js
  44. +0 −124 js/noms/src/chunk-serializer.js
  45. +0 −21 js/noms/src/chunk-store.js
  46. +0 −39 js/noms/src/chunk-test.js
  47. +0 −38 js/noms/src/chunk.js
  48. +0 −44 js/noms/src/collection.js
  49. +0 −94 js/noms/src/commit-test.js
  50. +0 −148 js/noms/src/commit.js
  51. +0 −118 js/noms/src/compare-test.js
  52. +0 −100 js/noms/src/compare.js
  53. +0 −314 js/noms/src/database-test.js
  54. +0 −185 js/noms/src/database.js
  55. +0 −42 js/noms/src/dataset-test.js
  56. +0 −76 js/noms/src/dataset.js
  57. +0 −28 js/noms/src/decode-value.js
  58. +0 −124 js/noms/src/edit-distance-test.js
  59. +0 −238 js/noms/src/edit-distance.js
  60. +0 −134 js/noms/src/encode-human-readable-test.js
  61. +0 −181 js/noms/src/encode-human-readable.js
  62. +0 −24 js/noms/src/encode-value.js
  63. +0 −622 js/noms/src/encoding-test.js
  64. +0 −44 js/noms/src/fetch-test.js
  65. +0 −114 js/noms/src/fetch.js
  66. +0 −19 js/noms/src/get-hash-test.js
  67. +0 −36 js/noms/src/get-hash.js
  68. +0 −72 js/noms/src/hash-test.js
  69. +0 −86 js/noms/src/hash.js
  70. +0 −69 js/noms/src/http-batch-store-test.js
  71. +0 −192 js/noms/src/http-batch-store.js
  72. +0 −39 js/noms/src/http-error-test.js
  73. +0 −27 js/noms/src/http-error.js
  74. +0 −113 js/noms/src/indexed-sequence-diff.js
  75. +0 −58 js/noms/src/indexed-sequence.js
  76. +0 −24 js/noms/src/jest.js
  77. +0 −81 js/noms/src/json-convert-test.js
  78. +0 −58 js/noms/src/json-convert.js
  79. +0 −701 js/noms/src/list-test.js
  80. +0 −231 js/noms/src/list.js
  81. +0 −827 js/noms/src/map-test.js
  82. +0 −230 js/noms/src/map.js
  83. +0 −66 js/noms/src/memory-store-test.js
  84. +0 −56 js/noms/src/memory-store.js
  85. +0 −58 js/noms/src/meta-sequence-test.js
  86. +0 −231 js/noms/src/meta-sequence.js
  87. +0 −70 js/noms/src/noms-kind.js
  88. +0 −22 js/noms/src/noms-reader.js
  89. +0 −20 js/noms/src/noms-writer.js
  90. +0 −74 js/noms/src/noms.js
  91. +0 −46 js/noms/src/number-util.js
  92. +0 −124 js/noms/src/ordered-sequence-diff-test.js
  93. +0 −111 js/noms/src/ordered-sequence-diff.js
  94. +0 −93 js/noms/src/ordered-sequence.js
  95. +0 −403 js/noms/src/path-test.js
  96. +0 −502 js/noms/src/path.js
  97. +0 −27 js/noms/src/primitives.js
  98. +0 −91 js/noms/src/put-cache-test.js
  99. +0 −300 js/noms/src/put-cache.js
  100. +0 −71 js/noms/src/ref.js
  101. +0 −47 js/noms/src/remote-batch-store-fake.js
  102. +0 −40 js/noms/src/remote-batch-store-test.js
  103. +0 −156 js/noms/src/remote-batch-store.js
  104. +0 −180 js/noms/src/rolling-value-hasher.js
  105. +0 −396 js/noms/src/sequence-chunker.js
  106. +0 −107 js/noms/src/sequence-test.js
  107. +0 −358 js/noms/src/sequence.js
  108. +0 −684 js/noms/src/set-test.js
  109. +0 −163 js/noms/src/set.js
  110. +0 −95 js/noms/src/signed-varint-test.js
  111. +0 −128 js/noms/src/signed-varint.js
  112. +0 −289 js/noms/src/spec-test.js
  113. +0 −327 js/noms/src/spec.js
  114. +0 −230 js/noms/src/specs-test.js
  115. +0 −219 js/noms/src/specs.js
  116. +0 −290 js/noms/src/struct-test.js
  117. +0 −423 js/noms/src/struct.js
  118. +0 −139 js/noms/src/test-util.js
  119. +0 −187 js/noms/src/type-cache-test.js
  120. +0 −496 js/noms/src/type-cache.js
  121. +0 −174 js/noms/src/type-test.js
  122. +0 −293 js/noms/src/type.js
  123. +0 −229 js/noms/src/value-decoder.js
  124. +0 −251 js/noms/src/value-encoder.js
  125. +0 −201 js/noms/src/value-store-test.js
  126. +0 −343 js/noms/src/value-store.js
  127. +0 −84 js/noms/src/value.js
  128. +0 −20 js/noms/src/version.js
  129. +0 −273 js/noms/src/walk-test.js
  130. +0 −113 js/noms/src/walk.js
  131. +0 −76 js/noms/src/xp-test.js
  132. +0 −4,917 js/noms/yarn.lock
  133. +0 −13 js/perf/.eslintrc.js
  134. +0 −5 js/perf/codec-perf-rig/.gitignore
  135. +0 −22 js/perf/codec-perf-rig/README.md
  136. +0 −23 js/perf/codec-perf-rig/package.json
  137. +0 −235 js/perf/codec-perf-rig/src/main.js
  138. +0 −2,597 js/perf/codec-perf-rig/yarn.lock
  139. +0 −5 js/perf/encode-perf-rig/.gitignore
  140. +0 −57 js/perf/encode-perf-rig/README.md
  141. +0 −23 js/perf/encode-perf-rig/package.json
  142. +0 −29 js/perf/encode-perf-rig/run.sh
  143. +0 −26 js/perf/encode-perf-rig/src/binary-encoder.js
  144. +0 −41 js/perf/encode-perf-rig/src/binary-int-encoder.js
  145. +0 −24 js/perf/encode-perf-rig/src/binary-varint-encoder.js
  146. +0 −10 js/perf/encode-perf-rig/src/encoder-type.js
  147. +0 −34 js/perf/encode-perf-rig/src/frexp.js
  148. +0 −95 js/perf/encode-perf-rig/src/main.js
  149. +0 −24 js/perf/encode-perf-rig/src/string-encoder.js
  150. +0 −2,601 js/perf/encode-perf-rig/yarn.lock
  151. +0 −5 js/perf/hash-perf-rig/.gitignore
  152. +0 −14 js/perf/hash-perf-rig/README.md
  153. +0 −23 js/perf/hash-perf-rig/package.json
  154. +0 −98 js/perf/hash-perf-rig/src/main.js
  155. +0 −2,621 js/perf/hash-perf-rig/yarn.lock
  156. +0 −5 js/perf/viewer/.gitignore
  157. +0 −15 js/perf/viewer/README.md
  158. +0 −13 js/perf/viewer/build.py
  159. +0 −11 js/perf/viewer/index.html
  160. +0 −10 js/perf/viewer/main.css
  161. +0 −15 js/perf/viewer/modules/Chart.bundle.min.js
  162. +0 −22 js/perf/viewer/package.json
  163. +0 −248 js/perf/viewer/src/main.js
  164. +0 −20 js/perf/viewer/stage.py
  165. +0 −2,859 js/perf/viewer/yarn.lock
  166. +0 −19 samples/js/README.md
  167. +0 −6 samples/js/aggregate/.gitignore
  168. +0 −7 samples/js/aggregate/dummy.go
  169. +0 −22 samples/js/aggregate/package.json
  170. +0 −94 samples/js/aggregate/src/main.js
  171. +0 −2,593 samples/js/aggregate/yarn.lock
  172. +0 −5 samples/js/bar-chart/.gitignore
  173. +0 −30 samples/js/bar-chart/README.md
  174. +0 −13 samples/js/bar-chart/index.html
  175. +0 −23 samples/js/bar-chart/package.json
  176. +0 −48 samples/js/bar-chart/plotly-1.9.0.min.js
  177. BIN samples/js/bar-chart/screenshot.png
  178. +0 −52 samples/js/bar-chart/src/main.js
  179. +0 −2,859 samples/js/bar-chart/yarn.lock
  180. +0 −5 samples/js/counter/.gitignore
  181. +0 −14 samples/js/counter/README.md
  182. +0 −7 samples/js/counter/dummy.go
  183. +0 −28 samples/js/counter/package.json
  184. +0 −49 samples/js/counter/src/main.js
  185. +0 −2,593 samples/js/counter/yarn.lock
  186. +0 −6 samples/js/fs/.gitignore
  187. +0 −7 samples/js/fs/dummy.go
  188. +0 −24 samples/js/fs/package.json
  189. +0 −164 samples/js/fs/src/main.js
  190. +0 −1 samples/js/fs/test-data.txt
  191. +0 −2,621 samples/js/fs/yarn.lock
  192. +0 −6 samples/js/splore/.gitignore
  193. +0 −28 samples/js/splore/README.md
  194. +0 −13 samples/js/splore/build.py
  195. +0 −12 samples/js/splore/index.html
  196. +0 −29 samples/js/splore/package.json
  197. BIN samples/js/splore/screenshot.png
  198. +0 −222 samples/js/splore/src/buchheim.js
  199. +0 −100 samples/js/splore/src/layout.js
  200. +0 −334 samples/js/splore/src/main.js
  201. +0 −100 samples/js/splore/src/node.js
  202. +0 −15 samples/js/splore/stage.py
  203. +0 −46 samples/js/splore/styles.css
  204. +0 −3,044 samples/js/splore/yarn.lock
  205. +0 −5 samples/js/url_fetch/.gitignore
  206. +0 −7 samples/js/url_fetch/dummy.go
  207. +0 −23 samples/js/url_fetch/package.json
  208. +0 −100 samples/js/url_fetch/src/main.js
  209. +0 −2,597 samples/js/url_fetch/yarn.lock
  210. +0 −46 tools/build-js-documentation.py
  211. +0 −1 tools/publish-to-npm.py
  212. +0 −30 tools/run-all-js-tests.py
  213. +0 −4 tools/run_pr_builder.sh
View
@@ -89,11 +89,7 @@ You can use `go test` command, e.g:
* `go test $(go list ./... | grep -v /vendor/)` should run every test except from vendor packages.
For JS code, We have a python script to run all js tests.
* `python tools/run-all-js-tests.py`
If you have commit rights, Jenkins automatically runs the Go and JS tests on every PR, then every subsequent patch. To ask Jenkins to immediately run, any committer can reply (no quotes) "Jenkins: test this" to your PR.
If you have commit rights, Jenkins automatically runs the Go tests on every PR, then every subsequent patch. To ask Jenkins to immediately run, any committer can reply (no quotes) "Jenkins: test this" to your PR.
### Perf tests
View
@@ -13,8 +13,3 @@ Here's what we have so far!
* [Go SDK Tour](go-tour.md)
* [Go SDK Reference](https://godoc.org/github.com/attic-labs/noms)
## JavaScript
* [JavaScript SDK Tour](js-tour.md)
* [JavaScript SDK Reference](http://docs.noms.io/js)
View
@@ -38,13 +38,28 @@ A database has two responsibilities: it provides storage of [content-addressed](
A Noms database can be implemented on top of any underlying storage system that provides key/value storage with at least optional optimistic concurrency. We only use optimistic concurrency to store the current value of each dataset. Chunks themselves are immutable.
We have implementations of Noms databases on top of our own file-backed store [Noms Block Store (NBS)](https://github.com/attic-labs/noms/tree/master/go/nbs) (usually used locally), our own [HTTP protocol](https://github.com/attic-labs/noms/blob/master/go/datas/database_server.go) (used for working with a remote database), [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), and [memory](https://github.com/attic-labs/noms/blob/master/js/noms/src/memory-store.js) (mainly used for testing).
We have implementations of Noms databases on top of our own file-backed store [Noms Block Store (NBS)](https://github.com/attic-labs/noms/tree/master/go/nbs) (usually used locally), our own [HTTP protocol](https://github.com/attic-labs/noms/blob/master/go/datas/database_server.go) (used for working with a remote database), [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), and [memory](https://github.com/attic-labs/noms/blob/master/go/chunks/memory_store.go) (mainly used for testing).
Here's an example of creating an http-backed database using the [JavaScript Noms SDK](js-tour.md):
Here's an example of creating an http-backed database using the [Go Noms SDK](go-tour.md):
```
var noms = require('@attic/noms');
var db = noms.DatabaseSpec.parse('http://localhost:8000').db();
```go
package main
import (
"fmt"
"os"
"github.com/attic-labs/noms/go/spec"
)
func main() {
sp, err := spec.ForDatabase("http://localhost:8000")
if err != nil {
fmt.Fprintf(os.Stderr, "Could not access database: %s\n", err)
return
}
defer sp.Close()
}
```
A dataset is nothing more than a named pointer into the DAG. Consider the following command to copy the dataset named `foo` to the dataset named `bar` within a database:
@@ -174,7 +189,7 @@ Because of this sorting, Noms collections can be used as efficient indexes, in t
For example, say you want to quickly be able to find `Person` structs by their age. You could build a map of type `Map<Number, Set<Person>>`. This would allow you to quickly (~log<sub>k</sub>(n) seeks, where `k` is average prolly tree width, which is currently 64) find all the people of an exact age. But it would _also_ allow you to find all people within a range of ages efficiently (~num_results/log<sub>k</sub>(n) seeks), even if the ages are non-integral.
Also, because Noms collections are ordered search trees, it is possible to implement set operations like union and [intersect](https://github.com/attic-labs/noms/blob/d6537c74c58fecebb8c4605c07b0670ed9737e1f/js/src/set.js#L157) efficiently on them.
Also, because Noms collections are ordered search trees, it is possible to implement set operations like union and intersect efficiently on them.
So, for example, if you wanted to find all the people of a particular age AND having a particular hair color, you could construct a second map having type `Map<String, Set<Person>>`, and intersect the two sets.
View
@@ -1,193 +0,0 @@
# A Short Tour of Noms for JavaScript
This is a short introduction to using Noms from JavaScript. It should only take a few minutes if you have some familiarity with JavaScript and Node.
During the tour, you can refer to the complete [JavaScript SDK Reference](https://docs.noms.io/js/) for more information on anything you see.
## Requirements
* [Noms command-line tools](https://github.com/attic-labs/noms#setup)
* [Node v5.11+](https://nodejs.org/en/)
## Start a Local Database
Let's create a local database to play with:
```sh
noms serve /tmp/noms-js-tour
```
## Install Noms NPM Package
Leave the server running, and in a separate terminal:
```sh
mkdir noms-tour
cd noms-tour
echo '{"name":"noms-tour","version":"0.0.1"}' > package.json
yarn add @attic/noms
```
Then launch Node so that we can have a play:
```sh
node
```
## [Database](https://github.com/attic-labs/noms/blob/master/js/noms/src/database.js)
To get started with Noms, first create a Database:
```js
const noms = require('@attic/noms');
const db = noms.DatabaseSpec.parse('http://localhost:8000').database();
```
See [Spelling in Noms](spelling.md) for more information on database spec strings.
## [Dataset](https://github.com/attic-labs/noms/blob/master/js/noms/src/dataset.js)
Datasets are the main interface you'll use to work with Noms. A dataset is just a named value in the database that you can update:
```js
let ds = db.getDataset('people');
// prints: null
ds.head().then(console.log);
let data = new noms.List([
noms.newStruct('', {
given: 'Rickon',
male: true,
}),
noms.newStruct('', {
given: 'Bran',
male: true,
}),
noms.newStruct('', {
given: 'Arya',
male: false,
}),
noms.newStruct('', {
given: 'Sansa',
male: false,
}),
]);
// prints:
// List<struct {
// given: String
// male: Bool
// }>
console.log(data.type.describe());
db.commit(ds, data).
then(r => ds = r);
```
Now we can explore the data:
```
// prints: Rickon
ds.head().
then(commit => commit.value.get(0)).
then(v => console.log(v.given));
```
You can also see this on the command-line. In a new (third) terminal:
```sh
> noms ds http://localhost:8000
people
> noms show http://localhost:8000::people
struct Commit {
parents: Set<Ref<Cycle<0>>>
value: Value
}({
parents: {},
value: [
{
given: "Rickon",
male: true,
},
...
```
Let's add some more data. Back in Node:
```js
data.append(noms.newStruct('', {
given: 'Jon',
family: 'Snow',
male: true,
})).then(d => data = d);
// prints:
// List<struct {
// family: String
// given: String
// male: Bool
// } | struct {
// given: String
// male: Bool
// }>
console.log(data.type.describe());
db.commit(ds, data).
then(r => ds = r);
```
Datasets are versioned. When you *commit* a new value, you aren't overwriting the old value, but adding to a historical log of values.
```js
function printCommit(commit) {
console.log('list', commit.value.hash.toString(),
'length:', commit.value.length);
if (commit.parents.isEmpty()) {
return;
}
commit.parents.first().
then(r => r.targetValue(db)).
then(printCommit);
}
// Prints:
// list sha1-eba46d10a2d1d10eb9f115c7b8df8c45653b430e length: 5
// list sha1-9cf762c697b10a2868957b6c4ea30de36608ac08 length: 4
ds.head().then(printCommit);
```
## Values
Noms supports a [variety of datatypes](intro.md#types). The following table summarizes the JavaScript datatype(s) used to represent each Noms datatype.
Noms Type | JavaScript Type
--------------- | ---------
Boolean | boolean
Number | number
String | string
Blob | noms.Blob
Set | noms.Set
List | noms.List
Map | noms.Map
Ref | noms.Ref
Struct | noms.Struct
In most cases, the Noms JavaScript library will automatically convert between JavaScript types and Noms types. For example:
```js
// Writes a noms value of type:
// Struct<foo: String, num: Number, list: List<String|Number>>
store.writeValue(newStruct('', {
foo: "bar",
num: 42,
list: new List("a", "b", 4, 8),
}));
```
Sometimes it's nice to explicitly control the type. You can do that by calling `new Struct` directy and passing a `Type` for the first parameter.
View
@@ -10,7 +10,7 @@ import (
"os"
)
// TODO: generate this from some central thing with go generate, so that JS and Go can be easily kept in sync
// TODO: generate this from some central thing with go generate.
const NomsVersion = "7.2"
const NOMS_VERSION_NEXT_ENV_NAME = "NOMS_VERSION_NEXT"
const NOMS_VERSION_NEXT_ENV_VALUE = "1"
View
@@ -69,9 +69,7 @@ func TestMemHashPathSpec(t *testing.T) {
assert.Equal("", spec.DatabaseName)
assert.False(spec.Path.IsEmpty())
// This would be a reasonable check, and the equivalent JS test does it, but
// it causes the next GetValue to return nil. This is inconsistent with JS.
// See https://github.com/attic-labs/noms/issues/2802:
// This is a reasonable check but it causes the next GetValue to return nil:
// assert.Nil(spec.GetValue())
spec.GetDatabase().WriteValue(s)
View
@@ -16,9 +16,6 @@ import (
"github.com/attic-labs/testify/suite"
)
// IMPORTANT: These tests and in particular the hash of the values should stay in sync with the
// corresponding tests in js
type countingReader struct {
last uint32
val uint32
View
@@ -22,7 +22,6 @@ type testSuite struct {
testValues []*testValue
}
// please update Go and JS to keep them in sync - see js/src//xp-test.js
func newTestSuite() *testSuite {
testValues := []*testValue{
{Bool(true), "g19moobgrm32dn083bokhksuobulq28c", "bool - true"},
View
@@ -1,3 +0,0 @@
{
"presets": ["noms"]
}
View
@@ -1,7 +0,0 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
module.exports = {
extends: 'noms',
};
View
@@ -1,20 +0,0 @@
[ignore]
.*/node_modules/babel.*
.*/node_modules/babylon/.*
.*/node_modules/d3/.*
.*/node_modules/fbjs/.*
.*/node_modules/react/.*
.*/node_modules/y18n/.*
.*/node_modules/json5/.*
[include]
[libs]
[options]
unsafe.enable_getters_and_setters=true
munge_underscores=true
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue: .+
[version]
^0.39.0
View
@@ -1,6 +0,0 @@
node_modules
dist
generated-docs
.nyc_output
coverage.lcov
coverage
View
@@ -1,7 +0,0 @@
build/
src/
.*
*.tgz
*-test.js
*-test.js.flow
coverage.lcov
View
@@ -1,17 +0,0 @@
<img src='https://github.com/attic-labs/noms/raw/master/doc/nommy_cropped_smaller.png' align='left' width='350' title='Nommy, the snacky otter'>
<br clear='all'/>
*[Noms](https://github.com/attic-labs/noms/)* is a content-addressed, immutable, decentralized, strongly-typed database.
In other words, Noms is Git for data.
This is the JavaScript reference implementation.
## Getting Started
The [JavaScript SDK Tour](https://github.com/attic-labs/noms/blob/master/doc/js-tour.md) walks you through installing and creating your first Noms database using NodeJS.
## More Info
[Command-Line Tour](doc/cli-tour.md)&nbsp; | &nbsp;[Go SDK Tour](doc/go-tour.md)&nbsp; | &nbsp;[Intro to Noms](doc/intro.md)
@@ -1,17 +0,0 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
'use strict';
const fs = require('fs-extra');
const path = require('path');
const outDir = path.join(__dirname, '..', 'generated-docs', 'js');
fs.mkdirsSync(outDir);
const version = require('../package.json').version;
const out = path.join(outDir, 'index.html');
fs.writeFileSync(out, `<script>
location.replace('./${version}/' + location.hash);
</script>`);
Oops, something went wrong.

0 comments on commit 3c764c1

Please sign in to comment.