diff options
| author | Divy Srivastava <dj.srivastava23@gmail.com> | 2023-02-20 22:22:28 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-20 22:22:28 +0530 |
| commit | ea7ca00c895c401af57a7201f3c41524333e7939 (patch) | |
| tree | a238ea54a003111ab6c1b7b1cb14e0669cb4f7af /ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base | |
| parent | a16c11c5d10052c688ba4c2eca09fd1a225e395a (diff) | |
perf: use ops for node:crypto ciphers (#17819)
Towards #17809
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base')
3 files changed, 0 insertions, 1039 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js deleted file mode 100644 index cb01476cd..000000000 --- a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -// Copyright 2017 Fedor Indutny. All rights reserved. MIT license. - -import { Reporter } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js"; -import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; - -export function DecoderBuffer(base, options) { - Reporter.call(this, options); - if (!Buffer.isBuffer(base)) { - this.error("Input not Buffer"); - return; - } - - this.base = base; - this.offset = 0; - this.length = base.length; -} -// inherits(DecoderBuffer, Reporter); -DecoderBuffer.prototype = Object.create(Reporter.prototype, { - constructor: { - value: DecoderBuffer, - enumerable: false, - writable: true, - configurable: true, - }, -}); - -DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) { - if (data instanceof DecoderBuffer) { - return true; - } - - // Or accept compatible API - const isCompatible = typeof data === "object" && - Buffer.isBuffer(data.base) && - data.constructor.name === "DecoderBuffer" && - typeof data.offset === "number" && - typeof data.length === "number" && - typeof data.save === "function" && - typeof data.restore === "function" && - typeof data.isEmpty === "function" && - typeof data.readUInt8 === "function" && - typeof data.skip === "function" && - typeof data.raw === "function"; - - return isCompatible; -}; - -DecoderBuffer.prototype.save = function save() { - return { offset: this.offset, reporter: Reporter.prototype.save.call(this) }; -}; - -DecoderBuffer.prototype.restore = function restore(save) { - // Return skipped data - const res = new DecoderBuffer(this.base); - res.offset = save.offset; - res.length = this.offset; - - this.offset = save.offset; - Reporter.prototype.restore.call(this, save.reporter); - - return res; -}; - -DecoderBuffer.prototype.isEmpty = function isEmpty() { - return this.offset === this.length; -}; - -DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { - if (this.offset + 1 <= this.length) { - return this.base.readUInt8(this.offset++, true); - } else { - return this.error(fail || "DecoderBuffer overrun"); - } -}; - -DecoderBuffer.prototype.skip = function skip(bytes, fail) { - if (!(this.offset + bytes <= this.length)) { - return this.error(fail || "DecoderBuffer overrun"); - } - - const res = new DecoderBuffer(this.base); - - // Share reporter state - res._reporterState = this._reporterState; - - res.offset = this.offset; - res.length = this.offset + bytes; - this.offset += bytes; - return res; -}; - -DecoderBuffer.prototype.raw = function raw(save) { - return this.base.slice(save ? save.offset : this.offset, this.length); -}; - -export function EncoderBuffer(value, reporter) { - if (Array.isArray(value)) { - this.length = 0; - this.value = value.map(function (item) { - if (!EncoderBuffer.isEncoderBuffer(item)) { - item = new EncoderBuffer(item, reporter); - } - this.length += item.length; - return item; - }, this); - } else if (typeof value === "number") { - if (!(0 <= value && value <= 0xff)) { - return reporter.error("non-byte EncoderBuffer value"); - } - this.value = value; - this.length = 1; - } else if (typeof value === "string") { - this.value = value; - this.length = Buffer.byteLength(value); - } else if (Buffer.isBuffer(value)) { - this.value = value; - this.length = value.length; - } else { - return reporter.error("Unsupported type: " + typeof value); - } -} - -EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) { - if (data instanceof EncoderBuffer) { - return true; - } - - // Or accept compatible API - const isCompatible = typeof data === "object" && - data.constructor.name === "EncoderBuffer" && - typeof data.length === "number" && - typeof data.join === "function"; - - return isCompatible; -}; - -EncoderBuffer.prototype.join = function join(out, offset) { - if (!out) { - out = Buffer.alloc(this.length); - } - if (!offset) { - offset = 0; - } - - if (this.length === 0) { - return out; - } - - if (Array.isArray(this.value)) { - this.value.forEach(function (item) { - item.join(out, offset); - offset += item.length; - }); - } else { - if (typeof this.value === "number") { - out[offset] = this.value; - } else if (typeof this.value === "string") { - out.write(this.value, offset); - } else if (Buffer.isBuffer(this.value)) { - this.value.copy(out, offset); - } - offset += this.length; - } - - return out; -}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js deleted file mode 100644 index 027778155..000000000 --- a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/node.js +++ /dev/null @@ -1,734 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -// Copyright 2017 Fedor Indutny. All rights reserved. MIT license. - -import { Reporter } from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js"; -import { - DecoderBuffer, - EncoderBuffer, -} from "internal:deno_node/polyfills/_crypto/crypto_browserify/asn1.js/base/buffer.js"; -import { assert } from "internal:deno_node/polyfills/_util/asserts.ts"; - -// Supported tags -const tags = [ - "seq", - "seqof", - "set", - "setof", - "objid", - "bool", - "gentime", - "utctime", - "null_", - "enum", - "int", - "objDesc", - "bitstr", - "bmpstr", - "charstr", - "genstr", - "graphstr", - "ia5str", - "iso646str", - "numstr", - "octstr", - "printstr", - "t61str", - "unistr", - "utf8str", - "videostr", -]; - -// Public methods list -const methods = [ - "key", - "obj", - "use", - "optional", - "explicit", - "implicit", - "def", - "choice", - "any", - "contains", -].concat(tags); - -// Overrided methods list -const overrided = [ - "_peekTag", - "_decodeTag", - "_use", - "_decodeStr", - "_decodeObjid", - "_decodeTime", - "_decodeNull", - "_decodeInt", - "_decodeBool", - "_decodeList", - - "_encodeComposite", - "_encodeStr", - "_encodeObjid", - "_encodeTime", - "_encodeNull", - "_encodeInt", - "_encodeBool", -]; - -export function Node(enc, parent, name) { - const state = {}; - this._baseState = state; - - state.name = name; - state.enc = enc; - - state.parent = parent || null; - state.children = null; - - // State - state.tag = null; - state.args = null; - state.reverseArgs = null; - state.choice = null; - state.optional = false; - state.any = false; - state.obj = false; - state.use = null; - state.useDecoder = null; - state.key = null; - state["default"] = null; - state.explicit = null; - state.implicit = null; - state.contains = null; - - // Should create new instance on each method - if (!state.parent) { - state.children = []; - this._wrap(); - } -} - -const stateProps = [ - "enc", - "parent", - "children", - "tag", - "args", - "reverseArgs", - "choice", - "optional", - "any", - "obj", - "use", - "alteredUse", - "key", - "default", - "explicit", - "implicit", - "contains", -]; - -Node.prototype.clone = function clone() { - const state = this._baseState; - const cstate = {}; - stateProps.forEach(function (prop) { - cstate[prop] = state[prop]; - }); - const res = new this.constructor(cstate.parent); - res._baseState = cstate; - return res; -}; - -Node.prototype._wrap = function wrap() { - const state = this._baseState; - methods.forEach(function (method) { - this[method] = function _wrappedMethod() { - const clone = new this.constructor(this); - state.children.push(clone); - return clone[method].apply(clone, arguments); - }; - }, this); -}; - -Node.prototype._init = function init(body) { - const state = this._baseState; - - assert(state.parent === null); - body.call(this); - - // Filter children - state.children = state.children.filter(function (child) { - return child._baseState.parent === this; - }, this); - assert(state.children.length === 1, "Root node can have only one child"); -}; - -Node.prototype._useArgs = function useArgs(args) { - const state = this._baseState; - - // Filter children and args - const children = args.filter(function (arg) { - return arg instanceof this.constructor; - }, this); - args = args.filter(function (arg) { - return !(arg instanceof this.constructor); - }, this); - - if (children.length !== 0) { - assert(state.children === null); - state.children = children; - - // Replace parent to maintain backward link - children.forEach(function (child) { - child._baseState.parent = this; - }, this); - } - if (args.length !== 0) { - assert(state.args === null); - state.args = args; - state.reverseArgs = args.map(function (arg) { - if (typeof arg !== "object" || arg.constructor !== Object) { - return arg; - } - - const res = {}; - Object.keys(arg).forEach(function (key) { - if (key == (key | 0)) { - key |= 0; - } - const value = arg[key]; - res[value] = key; - }); - return res; - }); - } -}; - -// -// Overrided methods -// - -overrided.forEach(function (method) { - Node.prototype[method] = function _overrided() { - const state = this._baseState; - throw new Error(method + " not implemented for encoding: " + state.enc); - }; -}); - -// -// Public methods -// - -tags.forEach(function (tag) { - Node.prototype[tag] = function _tagMethod() { - const state = this._baseState; - const args = Array.prototype.slice.call(arguments); - - assert(state.tag === null); - state.tag = tag; - - this._useArgs(args); - - return this; - }; -}); - -Node.prototype.use = function use(item) { - assert(item); - const state = this._baseState; - - assert(state.use === null); - state.use = item; - - return this; -}; - -Node.prototype.optional = function optional() { - const state = this._baseState; - - state.optional = true; - - return this; -}; - -Node.prototype.def = function def(val) { - const state = this._baseState; - - assert(state["default"] === null); - state["default"] = val; - state.optional = true; - - return this; -}; - -Node.prototype.explicit = function explicit(num) { - const state = this._baseState; - - assert(state.explicit === null && state.implicit === null); - state.explicit = num; - - return this; -}; - -Node.prototype.implicit = function implicit(num) { - const state = this._baseState; - - assert(state.explicit === null && state.implicit === null); - state.implicit = num; - - return this; -}; - -Node.prototype.obj = function obj() { - const state = this._baseState; - const args = Array.prototype.slice.call(arguments); - - state.obj = true; - - if (args.length !== 0) { - this._useArgs(args); - } - - return this; -}; - -Node.prototype.key = function key(newKey) { - const state = this._baseState; - - assert(state.key === null); - state.key = newKey; - - return this; -}; - -Node.prototype.any = function any() { - const state = this._baseState; - - state.any = true; - - return this; -}; - -Node.prototype.choice = function choice(obj) { - const state = this._baseState; - - assert(state.choice === null); - state.choice = obj; - this._useArgs( - Object.keys(obj).map(function (key) { - return obj[key]; - }), - ); - - return this; -}; - -Node.prototype.contains = function contains(item) { - const state = this._baseState; - - assert(state.use === null); - state.contains = item; - - return this; -}; - -// -// Decoding -// - -Node.prototype._decode = function decode(input, options) { - const state = this._baseState; - - // Decode root node - if (state.parent === null) { - return input.wrapResult(state.children[0]._decode(input, options)); - } - - let result = state["default"]; - let present = true; - - let prevKey = null; - if (state.key !== null) { - prevKey = input.enterKey(state.key); - } - - // Check if tag is there - if (state.optional) { - let tag = null; - if (state.explicit !== null) { - tag = state.explicit; - } else if (state.implicit !== null) { - tag = state.implicit; - } else if (state.tag !== null) { - tag = state.tag; - } - - if (tag === null && !state.any) { - // Trial and Error - const save = input.save(); - try { - if (state.choice === null) { - this._decodeGeneric(state.tag, input, options); - } else { - this._decodeChoice(input, options); - } - present = true; - } catch (_e) { - present = false; - } - input.restore(save); - } else { - present = this._peekTag(input, tag, state.any); - - if (input.isError(present)) { - return present; - } - } - } - - // Push object on stack - let prevObj; - if (state.obj && present) { - prevObj = input.enterObject(); - } - - if (present) { - // Unwrap explicit values - if (state.explicit !== null) { - const explicit = this._decodeTag(input, state.explicit); - if (input.isError(explicit)) { - return explicit; - } - input = explicit; - } - - const start = input.offset; - - // Unwrap implicit and normal values - if (state.use === null && state.choice === null) { - let save; - if (state.any) { - save = input.save(); - } - const body = this._decodeTag( - input, - state.implicit !== null ? state.implicit : state.tag, - state.any, - ); - if (input.isError(body)) { - return body; - } - - if (state.any) { - result = input.raw(save); - } else { - input = body; - } - } - - if (options && options.track && state.tag !== null) { - options.track(input.path(), start, input.length, "tagged"); - } - - if (options && options.track && state.tag !== null) { - options.track(input.path(), input.offset, input.length, "content"); - } - - // Select proper method for tag - if (state.any) { - // no-op - } else if (state.choice === null) { - result = this._decodeGeneric(state.tag, input, options); - } else { - result = this._decodeChoice(input, options); - } - - if (input.isError(result)) { - return result; - } - - // Decode children - if (!state.any && state.choice === null && state.children !== null) { - state.children.forEach(function decodeChildren(child) { - // NOTE: We are ignoring errors here, to let parser continue with other - // parts of encoded data - child._decode(input, options); - }); - } - - // Decode contained/encoded by schema, only in bit or octet strings - if (state.contains && (state.tag === "octstr" || state.tag === "bitstr")) { - const data = new DecoderBuffer(result); - result = this._getUse(state.contains, input._reporterState.obj) - ._decode(data, options); - } - } - - // Pop object - if (state.obj && present) { - result = input.leaveObject(prevObj); - } - - // Set key - if (state.key !== null && (result !== null || present === true)) { - input.leaveKey(prevKey, state.key, result); - } else if (prevKey !== null) { - input.exitKey(prevKey); - } - - return result; -}; - -Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) { - const state = this._baseState; - - if (tag === "seq" || tag === "set") { - return null; - } - if (tag === "seqof" || tag === "setof") { - return this._decodeList(input, tag, state.args[0], options); - } else if (/str$/.test(tag)) { - return this._decodeStr(input, tag, options); - } else if (tag === "objid" && state.args) { - return this._decodeObjid(input, state.args[0], state.args[1], options); - } else if (tag === "objid") { - return this._decodeObjid(input, null, null, options); - } else if (tag === "gentime" || tag === "utctime") { - return this._decodeTime(input, tag, options); - } else if (tag === "null_") { - return this._decodeNull(input, options); - } else if (tag === "bool") { - return this._decodeBool(input, options); - } else if (tag === "objDesc") { - return this._decodeStr(input, tag, options); - } else if (tag === "int" || tag === "enum") { - return this._decodeInt(input, state.args && state.args[0], options); - } - - if (state.use !== null) { - return this._getUse(state.use, input._reporterState.obj) - ._decode(input, options); - } else { - return input.error("unknown tag: " + tag); - } -}; - -Node.prototype._getUse = function _getUse(entity, obj) { - const state = this._baseState; - // Create altered use decoder if implicit is set - state.useDecoder = this._use(entity, obj); - assert(state.useDecoder._baseState.parent === null); - state.useDecoder = state.useDecoder._baseState.children[0]; - if (state.implicit !== state.useDecoder._baseState.implicit) { - state.useDecoder = state.useDecoder.clone(); - state.useDecoder._baseState.implicit = state.implicit; - } - return state.useDecoder; -}; - -Node.prototype._decodeChoice = function decodeChoice(input, options) { - const state = this._baseState; - let result = null; - let match = false; - - Object.keys(state.choice).some(function (key) { - const save = input.save(); - const node = state.choice[key]; - try { - const value = node._decode(input, options); - if (input.isError(value)) { - return false; - } - - result = { type: key, value: value }; - match = true; - } catch (_e) { - input.restore(save); - return false; - } - return true; - }, this); - - if (!match) { - return input.error("Choice not matched"); - } - - return result; -}; - -// -// Encoding -// - -Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { - return new EncoderBuffer(data, this.reporter); -}; - -Node.prototype._encode = function encode(data, reporter, parent) { - const state = this._baseState; - if (state["default"] !== null && state["default"] === data) { - return; - } - - const result = this._encodeValue(data, reporter, parent); - if (result === undefined) { - return; - } - - if (this._skipDefault(result, reporter, parent)) { - return; - } - - return result; -}; - -Node.prototype._encodeValue = function encode(data, reporter, parent) { - const state = this._baseState; - - // Decode root node - if (state.parent === null) { - return state.children[0]._encode(data, reporter || new Reporter()); - } - - let result = null; - - // Set reporter to share it with a child class - this.reporter = reporter; - - // Check if data is there - if (state.optional && data === undefined) { - if (state["default"] !== null) { - data = state["default"]; - } else { - return; - } - } - - // Encode children first - let content = null; - let primitive = false; - if (state.any) { - // Anything that was given is translated to buffer - result = this._createEncoderBuffer(data); - } else if (state.choice) { - result = this._encodeChoice(data, reporter); - } else if (state.contains) { - content = this._getUse(state.contains, parent)._encode(data, reporter); - primitive = true; - } else if (state.children) { - content = state.children.map(function (child) { - if (child._baseState.tag === "null_") { - return child._encode(null, reporter, data); - } - - if (child._baseState.key === null) { - return reporter.error("Child should have a key"); - } - const prevKey = reporter.enterKey(child._baseState.key); - - if (typeof data !== "object") { - return reporter.error("Child expected, but input is not object"); - } - - const res = child._encode(data[child._baseState.key], reporter, data); - reporter.leaveKey(prevKey); - - return res; - }, this).filter(function (child) { - return child; - }); - content = this._createEncoderBuffer(content); - } else { - if (state.tag === "seqof" || state.tag === "setof") { - // TODO(indutny): this should be thrown on DSL level - if (!(state.args && state.args.length === 1)) { - return reporter.error("Too many args for : " + state.tag); - } - - if (!Array.isArray(data)) { - return reporter.error("seqof/setof, but data is not Array"); - } - - const child = this.clone(); - child._baseState.implicit = null; - content = this._createEncoderBuffer(data.map(function (item) { - const state = this._baseState; - - return this._getUse(state.args[0], data)._encode(item, reporter); - }, child)); - } else if (state.use !== null) { - result = this._getUse(state.use, parent)._encode(data, reporter); - } else { - content = this._encodePrimitive(state.tag, data); - primitive = true; - } - } - - // Encode data itself - if (!state.any && state.choice === null) { - const tag = state.implicit !== null ? state.implicit : state.tag; - const cls = state.implicit === null ? "universal" : "context"; - - if (tag === null) { - if (state.use === null) { - reporter.error("Tag could be omitted only for .use()"); - } - } else { - if (state.use === null) { - result = this._encodeComposite(tag, primitive, cls, content); - } - } - } - - // Wrap in explicit - if (state.explicit !== null) { - result = this._encodeComposite(state.explicit, false, "context", result); - } - - return result; -}; - -Node.prototype._encodeChoice = function encodeChoice(data, reporter) { - const state = this._baseState; - - const node = state.choice[data.type]; - if (!node) { - assert( - false, - data.type + " not found in " + - JSON.stringify(Object.keys(state.choice)), - ); - } - return node._encode(data.value, reporter); -}; - -Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { - const state = this._baseState; - - if (/str$/.test(tag)) { - return this._encodeStr(data, tag); - } else if (tag === "objid" && state.args) { - return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); - } else if (tag === "objid") { - return this._encodeObjid(data, null, null); - } else if (tag === "gentime" || tag === "utctime") { - return this._encodeTime(data, tag); - } else if (tag === "null_") { - return this._encodeNull(); - } else if (tag === "int" || tag === "enum") { - return this._encodeInt(data, state.args && state.reverseArgs[0]); - } else if (tag === "bool") { - return this._encodeBool(data); - } else if (tag === "objDesc") { - return this._encodeStr(data, tag); - } else { - throw new Error("Unsupported tag: " + tag); - } -}; - -Node.prototype._isNumstr = function isNumstr(str) { - return /^[0-9 ]*$/.test(str); -}; - -Node.prototype._isPrintstr = function isPrintstr(str) { - return /^[A-Za-z0-9 '()+,-./:=?]*$/.test(str); -}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js b/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js deleted file mode 100644 index 509f6c5b3..000000000 --- a/ext/node/polyfills/_crypto/crypto_browserify/asn1.js/base/reporter.js +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -// Copyright 2017 Fedor Indutny. All rights reserved. MIT license. - -export function Reporter(options) { - this._reporterState = { - obj: null, - path: [], - options: options || {}, - errors: [], - }; -} - -Reporter.prototype.isError = function isError(obj) { - return obj instanceof ReporterError; -}; - -Reporter.prototype.save = function save() { - const state = this._reporterState; - - return { obj: state.obj, pathLen: state.path.length }; -}; - -Reporter.prototype.restore = function restore(data) { - const state = this._reporterState; - - state.obj = data.obj; - state.path = state.path.slice(0, data.pathLen); -}; - -Reporter.prototype.enterKey = function enterKey(key) { - return this._reporterState.path.push(key); -}; - -Reporter.prototype.exitKey = function exitKey(index) { - const state = this._reporterState; - - state.path = state.path.slice(0, index - 1); -}; - -Reporter.prototype.leaveKey = function leaveKey(index, key, value) { - const state = this._reporterState; - - this.exitKey(index); - if (state.obj !== null) { - state.obj[key] = value; - } -}; - -Reporter.prototype.path = function path() { - return this._reporterState.path.join("/"); -}; - -Reporter.prototype.enterObject = function enterObject() { - const state = this._reporterState; - - const prev = state.obj; - state.obj = {}; - return prev; -}; - -Reporter.prototype.leaveObject = function leaveObject(prev) { - const state = this._reporterState; - - const now = state.obj; - state.obj = prev; - return now; -}; - -Reporter.prototype.error = function error(msg) { - let err; - const state = this._reporterState; - - const inherited = msg instanceof ReporterError; - if (inherited) { - err = msg; - } else { - err = new ReporterError( - state.path.map(function (elem) { - return "[" + JSON.stringify(elem) + "]"; - }).join(""), - msg.message || msg, - msg.stack, - ); - } - - if (!state.options.partial) { - throw err; - } - - if (!inherited) { - state.errors.push(err); - } - - return err; -}; - -Reporter.prototype.wrapResult = function wrapResult(result) { - const state = this._reporterState; - if (!state.options.partial) { - return result; - } - - return { - result: this.isError(result) ? null : result, - errors: state.errors, - }; -}; - -function ReporterError(path, msg) { - this.path = path; - this.rethrow(msg); -} -// inherits(ReporterError, Error); -ReporterError.prototype = Object.create(Error.prototype, { - constructor: { - value: ReporterError, - enumerable: false, - writable: true, - configurable: true, - }, -}); - -ReporterError.prototype.rethrow = function rethrow(msg) { - this.message = msg + " at: " + (this.path || "(shallow)"); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, ReporterError); - } - - if (!this.stack) { - try { - // IE only adds stack when thrown - throw new Error(this.message); - } catch (e) { - this.stack = e.stack; - } - } - return this; -}; |
