Commit be3abc83 by Vladislav Lagunoff

[update] Добавлен Difference

parent fd01e2ae
......@@ -12,10 +12,10 @@ Update.Do = Do;
declare module "./" {
interface UpdateStatic {
Do<State, Result>(iter: () => IterableIterator<Update<any, any>>): Update<State, Result>;
Do<State, Result>(iter: () => IterableIterator<Update<Error, any, any>>): Update<Error, State, Result>;
}
interface BoundStatics<State> {
Do<Result>(iter: () => IterableIterator<Update<any, any>>): Update<State, Result>;
interface BoundStatics<Error, State> {
Do<Result>(iter: () => IterableIterator<Update<Error, any, any>>): Update<Error, State, Result>;
}
}
......
......@@ -5,23 +5,32 @@ import { absurd } from '../types';
// ADT
export type Update<State, A> =
| Pure<State, A> // { value: A }
| Modify<State, A> // { proj(x: State): State } // A ~ void
| Patch<State, A> // { patch: Partial<State> } // A ~ void
| Get<State, A> // { tag: 'Get' } // A ~ State
| Children<State, A> // { key: ControlledComponent<any, any>, update: Update<any, A> }
| Effect<State, A> // { effect: Eff<never, A> }
| FromPromise<State, A> // { promise: Promise<A> }
| Chain<State, A> // { update: Update<State, any>, chain(x: any): Update<State, A> }
| Apply<State, A> // { args: Update<State, any>[], proj(...args): A }
| Batch<State, A> // { steps: Updte<State, any>[] }
| Concat<State, A> // { steps: Updte<State, any>[] }
export type Update<Error, State, A> =
| Pure<Error, State, A> // { value: A }
| Modify<Error, State, A> // { proj(x: State): State } // A ~ void
| Patch<Error, State, A> // { patch: Partial<State> } // A ~ void
| Get<Error, State, A> // { tag: 'Get' } // A ~ State
| Children<Error, State, A> // { component: React.Component<any, any>, update: Update<any, A> }
| Effect<Error, State, A> // { effect: Eff<never, A> }
| FromPromise<Error, State, A> // { promise: Promise<A> }
| Chain<Error, State, A> // { update: Update<Error, State, any>, chain(x: any): Update<Error, State, A> }
| Apply<Error, State, A> // { args: Update<Error, State, any>[], proj(...args): A }
| Batch<Error, State, A> // { steps: Updte<Error, State, any>[] }
| Concat<Error, State, A> // { steps: Updte<Error, State, any>[] }
| Difference<Error, State, A> // { update: Update<A>, difference(prev: State, next: State): State|Update<Error, State, void> }
;
export type AnyUpdate = Update<any, any, any>;
// Perform state update
export function go<State, A>(update: Update<State, A>, component: React.Component<any, State>, onNext: (x: A) => void, onComplete: () => void): () => void {
export function go<Error, State, A>(
update: Update<Error, State, A>,
getState: () => State,
setState: SetState<State>,
onNext: (x: A) => void,
onError: (x: Error) => void,
onComplete: () => void
): Canceller {
if (update instanceof Pure) {
onNext(update.value);
onComplete();
......@@ -29,7 +38,7 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
}
if (update instanceof Modify) {
component['updater'].enqueueSetState(component, update.proj, () => {
setState(update.proj, () => {
onNext(void 0 as any);
update.callback && update.callback();
onComplete();
......@@ -38,7 +47,7 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
}
if (update instanceof Patch) {
component['updater'].enqueueSetState(component, update.patch, () => {
setState(update.patch, () => {
onNext(void 0 as any);
update.callback && update.callback();
onComplete();
......@@ -47,17 +56,19 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
}
if (update instanceof Get) {
onNext(component.state as any);
onNext(getState() as any as A);
onComplete();
return noopFunc;
}
if (update instanceof Children) {
return go(update.update, update.component, onNext, onComplete);
const _getState = () => update.component.state;
const _setState: SetState<any> = (projOrPatch, cb?) => update.component['updater'].enqueueSetState(update.component, projOrPatch, cb);
return go(update.update, _getState, _setState, onNext, onError, onComplete);
}
if (update instanceof Effect) {
return update.effect.run(onNext as any, onComplete);
return update.effect.run(ethr => ethr.fold(onError, onNext), onComplete);
}
if (update instanceof FromPromise) {
......@@ -66,23 +77,27 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
}
if (update instanceof Chain) {
const subscriptions: Array<Function|null> = [];
subscriptions.push(go(update.update, component, result => {
const idx = subscriptions.length;
subscriptions.push(go(update.andThen(result), component, onNext, () => {
subscriptions[idx] = null;
for (const unsub of subscriptions) if (unsub !== null) return;
onComplete();
}));
}, () => {
subscriptions[0] = null;
for (const unsub of subscriptions) if (unsub !== null) return;
onComplete();
}));
const cancellers = new Map<AnyUpdate, Canceller>();
const handleUpdate = (u: AnyUpdate) => {
const _onNext = result => {
if (u === update.update) handleUpdate(update.andThen(result));
else onNext(result);
};
const _onComplete = () => {
if (!cancellers.has(u)) completedImmediately = true;
cancellers.delete(u);
if (cancellers.size === 0) onComplete();
};
let completedImmediately = false;
const canceller = go(u, getState, setState as any, _onNext, onError, _onComplete);
if (!completedImmediately) cancellers.set(u, canceller);
};
handleUpdate(update.update);
if (cancellers.size === 0) return noopFunc;
return () => subscriptions.forEach(
funOrNull => funOrNull ? funOrNull() : void 0
);
return () => cancellers.forEach(canceller => canceller());
}
if (update instanceof Apply) {
......@@ -107,7 +122,7 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
};
update.args.forEach((u, idx) => {
const canceller = go(u, component, next(idx), complete(idx));
const canceller = go(u, getState, setState, next(idx), onError, complete(idx));
if (subscriptions[idx] !== null) subscriptions[idx] = canceller;
});
......@@ -125,7 +140,7 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
onNext(void 0 as any);
onComplete(); // If control flow reaches here, that means all nested commands are completed
};
subscriptions = update.steps.map((u, idx) => go(u, component, noopFunc, loop(idx)));
subscriptions = update.steps.map((u, idx) => go(u, getState, setState, noopFunc, onError, loop(idx)));
return () => subscriptions.forEach(
funOrNull => funOrNull ? funOrNull() : void 0
......@@ -137,180 +152,239 @@ export function go<State, A>(update: Update<State, A>, component: React.Componen
const loop = idx => () => {
// If condition holds, then all nested effects are completed, therefore we're done
if (idx >= update.steps.length) { onNext(void 0 as any); onComplete(); return; }
unsubscribe = go(update.steps[idx], component, noopFunc, loop(idx + 1));
unsubscribe = go(update.steps[idx], getState, setState, noopFunc, onError, loop(idx + 1));
};
loop(0);
return () => unsubscribe ? unsubscribe() : void 0;
}
if (update instanceof Difference) {
const cancellers = new Map<AnyUpdate, Canceller>();
const _setState: SetState<State> = (patchOrProj, cb?) => {
const prev = getState();
// @ts-ignore
const next = typeof(patchOrProj) === 'function' ? patchOrProj(prev) : { ...prev, ...patchOrProj };
const stateOrUpdate = update.difference(prev, next);
if (stateOrUpdate instanceof UpdateBase) {
handleUpdate(stateOrUpdate);
} else {
setState(() => stateOrUpdate, cb);
}
};
const handleUpdate = (u: AnyUpdate) => {
const _onNext = result => {
if (u === update.update) onNext(result);
// Just ignore `void` result from spawned processes
};
const _onComplete = () => {
if (!cancellers.has(u)) completedImmediately = true;
cancellers.delete(u);
if (cancellers.size === 0) onComplete();
};
let completedImmediately = false;
const canceller = go(u, getState, u === update.update ? _setState : setState as any, _onNext, onError, _onComplete);
if (!completedImmediately) cancellers.set(u, canceller);
};
handleUpdate(update.update);
if (cancellers.size === 0) return noopFunc;
return () => cancellers.forEach(canceller => canceller());
}
return absurd(update);
}
// Instance methods
export class UpdateBase<State, A> {
export class UpdateBase<Error, State, A> {
readonly _Error: Error;
readonly _State: State;
readonly _A: A;
map<B>(proj: (x: A) => B): Apply<State, B> {
const self = this as any as Update<State, A>;
return new Apply<State, B>([self], proj);
map<B>(proj: (x: A) => B): Apply<Error, State, B> {
const self = this as any as Update<Error, State, A>;
return new Apply<Error, State, B>([self], proj);
}
mapTo<B>(value: B): Apply<State, B> {
const self = this as any as Update<State, A>;
return new Apply<State, B>([self], () => value);
mapTo<B>(value: B): Apply<Error, State, B> {
const self = this as any as Update<Error, State, A>;
return new Apply<Error, State, B>([self], () => value);
}
chain<B,State2>(andThen: (x: A) => Update<State2, B>): Chain<State&State2, B>;
chain<B>(andThen: (x: A) => Update<State, B>): Chain<State, B>;
chain<B>(andThen: (x: A) => Update<State, B>): Chain<State, B> {
const self = this as any as Update<State, A>;
return new Chain<State, B>(self, andThen);
chain<B,State2>(andThen: (x: A) => Update<Error, State2, B>): Chain<Error, State&State2, B>;
chain<B>(andThen: (x: A) => Update<Error, State, B>): Chain<Error, State, B>;
chain<B>(andThen: (x: A) => Update<Error, State, B>): Chain<Error, State, B> {
const self = this as any as Update<Error, State, A>;
return new Chain<Error, State, B>(self, andThen);
}
chainTo<B,State2>(value: Update<State2, B>): Chain<State&State2, B>;
chainTo<B>(value: Update<State, B>): Chain<State, B>;
chainTo<B>(value: Update<State, B>): Chain<State, B> {
const self = this as any as Update<State, A>;
return new Chain<State, B>(self, () => value);
chainTo<B,State2>(value: Update<Error, State2, B>): Chain<Error, State&State2, B>;
chainTo<B>(value: Update<Error, State, B>): Chain<Error, State, B>;
chainTo<B>(value: Update<Error, State, B>): Chain<Error, State, B> {
const self = this as any as Update<Error, State, A>;
return new Chain<Error, State, B>(self, () => value);
}
run(component: React.Component<any, State>, onNext?: (x: A) => void, onComplete?: () => void): () => void {
const self = this as any as Update<State, A>;
return go(self, component, onNext || noopFunc, onComplete || noopFunc);
run(component: React.Component<any, State>, onNext?: (x: A) => void, onError?: (x: Error) => void, onComplete?: () => void): Canceller {
const self = this as any as Update<Error, State, A>;
const getState = () => component.state;
const setState: SetState<State> = (projOrPatch, cb?) => component['updater'].enqueueSetState(component, projOrPatch, cb);
return go(self, getState, setState, onNext || noopFunc, onError || noopFunc, onComplete || noopFunc);
}
pending(): Update<State & { pending: boolean }, A> {
pending(): Update<Error, State & { pending: boolean }, A> {
// @ts-ignore
return patch({ pending: true }).chainTo(this.chain(value => patch({ pending: false }).mapTo(value)));
}
}
export function ap<State,A,B>(a: Update<State,A>, f: (a: A) => B): Update<State,B>;
export function ap<State,A,B,C>(a: Update<State,A>, b: Update<State,B>, f: (a: A, b: B) => C): Update<State,C>;
export function ap<State,A,B,C,D>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, f: (a: A, b: B, c: C) => D): Update<State,D>;
export function ap<State,A,B,C,D,E>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, f: (a: A, b: B, c: C, d: D) => E): Update<State,E>;
export function ap<State,A,B,C,D,E,F>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, e: Update<State,E>, f: (a: A, b: B, c: C, d: D, e: E) => F): Update<State,F>;
export function ap<State,A,B,C,D,E,F,G>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, e: Update<State,E>, f_: Update<State,F>, f: (a: A, b: B, c: C, d: D, e: E, f: F) => G): Update<State,G>;
export function ap(): Update<unknown, unknown> {
// SetState
export type SetState<State> = {
(patch: Partial<State>, cb?: () => void): void;
(proj: (x: State) => State, cb?: () => void): void;
};
export function ap<Error, State,A,B>(a: Update<Error, State,A>, f: (a: A) => B): Update<Error, State,B>;
export function ap<Error, State,A,B,C>(a: Update<Error, State,A>, b: Update<Error, State,B>, f: (a: A, b: B) => C): Update<Error, State,C>;
export function ap<Error, State,A,B,C,D>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, f: (a: A, b: B, c: C) => D): Update<Error, State,D>;
export function ap<Error, State,A,B,C,D,E>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, f: (a: A, b: B, c: C, d: D) => E): Update<Error, State,E>;
export function ap<Error, State,A,B,C,D,E,F>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, e: Update<Error, State,E>, f: (a: A, b: B, c: C, d: D, e: E) => F): Update<Error, State,F>;
export function ap<Error, State,A,B,C,D,E,F,G>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, e: Update<Error, State,E>, f_: Update<Error, State,F>, f: (a: A, b: B, c: C, d: D, e: E, f: F) => G): Update<Error, State,G>;
export function ap(): Update<unknown, unknown, unknown> {
const args = Array.prototype.slice.call(arguments, 0, arguments.length - 1);
const proj = arguments[arguments.length - 1];
return new Apply(args, proj);
}
export function of<A>(value: A): Pure<never, A> {
export function of<A>(value: A): Pure<never, {}, A> {
return new Pure(value);
}
export function patch<State>(patch: Partial<State>, callback?: () => void): Patch<State, void> {
export function patch<State>(patch: Partial<State>, callback?: () => void): Patch<never, State, void> {
return new Patch(patch, callback);
}
export function modify<State>(proj: (x: State) => State, callback?: () => void): Modify<State, void> {
export function modify<State>(proj: (x: State) => State, callback?: () => void): Modify<never, State, void> {
return new Modify(proj, callback);
}
export function effect<Error, Success>(eff: Eff<Error, Success>): Effect<{}, Either<Error, Success>> {
export function effect<Error, Success>(eff: Eff<Error, Success>): Effect<Error, {}, Success> {
return new Effect(eff as any);
}
export function batch<State>(...steps: Update<State, any>[]): Batch<State, void>;
export function batch<State>(steps: Update<State, any>[]): Batch<State, void>;
export function batch(): Batch<unknown, void> {
export function batch<Error, State>(...steps: Update<Error, State, any>[]): Batch<Error, State, void>;
export function batch<Error, State>(steps: Update<Error, State, any>[]): Batch<Error, State, void>;
export function batch(): Batch<never, unknown, void> {
const steps = Array.isArray(arguments[0]) ? arguments[0] : arguments;
return new Batch(steps);
}
export function concat<State>(...steps: Update<State, any>[]): Concat<State, void>;
export function concat<State>(steps: Update<State, any>[]): Concat<State, void>;
export function concat(): Concat<unknown, void> {
export function concat<Error, State>(...steps: Update<Error, State, any>[]): Concat<Error, State, void>;
export function concat<Error, State>(steps: Update<Error, State, any>[]): Concat<Error, State, void>;
export function concat(): Concat<never, unknown, void> {
const steps = Array.isArray(arguments[0]) ? arguments[0] : arguments;
return new Concat(steps);
}
export function difference<Error, State, A>(update: Update<Error, State, A>, diff: (prev: State, next: State) => State|Update<Error, State, void>): Difference<Error, State, A> {
return new Difference(update, diff);
}
class Pure<State, A> extends UpdateBase<State, A> {
class Pure<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly value: A,
) { super(); }
}
class Modify<State, A> extends UpdateBase<State, A> {
class Modify<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly proj: (x: State) => State,
readonly callback?: () => void,
) { super(); }
}
class Patch<State, A> extends UpdateBase<State, A> {
class Patch<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly patch: Partial<State>,
readonly callback?: () => void,
) { super(); }
}
class Get<State, A> extends UpdateBase<State, A> {
class Get<Error, State, A> extends UpdateBase<Error, State, A> {
}
class Children<State, A> extends UpdateBase<State, A> {
class Children<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly component: React.Component<any, any>,
readonly update: Update<any, A>
readonly update: Update<never, {}, A>
) { super(); }
}
class Effect<State, A> extends UpdateBase<State, A> {
class Effect<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly effect: Eff<never, A>,
readonly effect: Eff<Error, A>,
) { super(); }
}
class FromPromise<State, A> extends UpdateBase<State, A> {
class FromPromise<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly promise: () => Promise<A>,
) { super(); }
}
class Chain<State, A> extends UpdateBase<State, A> {
class Chain<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly update: Update<State, any>,
readonly andThen: (x: any) => Update<State, A>,
readonly update: Update<Error, State, any>,
readonly andThen: (x: any) => Update<Error, State, A>,
) { super(); }
}
class Apply<State, A> extends UpdateBase<State, A> {
class Apply<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly args: Update<State, any>[],
readonly args: Update<Error, State, any>[],
readonly proj: (...args) => A,
) { super(); }
}
class Batch<State, A> extends UpdateBase<State, A> {
class Batch<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly steps: Update<Error, State, any>[],
) { super(); }
}
class Concat<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly steps: Update<State, any>[],
readonly steps: Update<Error, State, any>[],
) { super(); }
}
class Concat<State, A> extends UpdateBase<State, A> {
class Difference<Error, State, A> extends UpdateBase<Error, State, A> {
constructor(
readonly steps: Update<State, any>[],
readonly update: Update<Error, State, A>,
readonly difference: (prev: State, next: State) => State|Update<Error, State, void>,
) { super(); }
}
// Functional helpers
const noopFunc = () => {};
export type Canceller = () => void;
export const get = new Get();
export const get = new Get<never, {}, void>();
export class Component<Props, State> extends React.Component<Props, State> {
export class Component<Error, Props, State> extends React.Component<Props, State> {
constructor(props, context) {
super(props, context);
// @ts-ignore
......@@ -321,7 +395,7 @@ export class Component<Props, State> extends React.Component<Props, State> {
state: ((prevState: Readonly<State>, props: Readonly<Props>) => (Pick<State, K> | State | null)) | (Pick<State, K> | State | null),
callback?: () => void
): void;
setState(update: Update<State, void>, callback?: () => void): void;
setState(update: Update<Error, State, void>, callback?: () => void): void;
setState(updateOrProjOrPatch, callback?) {
if (updateOrProjOrPatch instanceof UpdateBase) {
const onUpdate = this.props['onUpdate'] as unknown;
......@@ -334,9 +408,9 @@ export class Component<Props, State> extends React.Component<Props, State> {
}
if (typeof(updateOrProjOrPatch) === 'function') {
return this.setState(new Modify<State, void>(updateOrProjOrPatch, callback))
return this.setState(new Modify<Error, State, void>(updateOrProjOrPatch, callback))
} else {
return this.setState(new Patch<State, void>(updateOrProjOrPatch, callback))
return this.setState(new Patch<Error, State, void>(updateOrProjOrPatch, callback))
}
}
}
......@@ -368,26 +442,26 @@ export const Update = {
bind,
} as UpdateStatic;
export interface BoundStatics<State> {
ap<A,B,C>(a: Update<State,A>, b: Update<State,B>, f: (a: A, b: B) => C): Apply<State,C>;
ap<A,B,C,D>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, f: (a: A, b: B, c: C) => D): Apply<State,D>;
ap<A,B,C,D,E>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, f: (a: A, b: B, c: C, d: D) => E): Apply<State,E>;
ap<A,B,C,D,E,F>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, e: Update<State,E>, f: (a: A, b: B, c: C, d: D, e: E) => F): Apply<State,F>;
ap<A,B,C,D,E,F,G>(a: Update<State,A>, b: Update<State,B>, c: Update<State,C>, d: Update<State,D>, e: Update<State,E>, f_: Update<State,F>, f: (a: A, b: B, c: C, d: D, e: E, f: F) => G): Apply<State,G>;
export interface BoundStatics<Error, State> {
ap<A,B,C>(a: Update<Error, State,A>, b: Update<Error, State,B>, f: (a: A, b: B) => C): Apply<Error, State,C>;
ap<A,B,C,D>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, f: (a: A, b: B, c: C) => D): Apply<Error, State,D>;
ap<A,B,C,D,E>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, f: (a: A, b: B, c: C, d: D) => E): Apply<Error, State,E>;
ap<A,B,C,D,E,F>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, e: Update<Error, State,E>, f: (a: A, b: B, c: C, d: D, e: E) => F): Apply<Error, State,F>;
ap<A,B,C,D,E,F,G>(a: Update<Error, State,A>, b: Update<Error, State,B>, c: Update<Error, State,C>, d: Update<Error, State,D>, e: Update<Error, State,E>, f_: Update<Error, State,F>, f: (a: A, b: B, c: C, d: D, e: E, f: F) => G): Apply<Error, State,G>;
batch(...steps: Update<State, any>[]): Batch<State, void>;
batch(steps: Update<State, any>[]): Batch<State, void>;
batch(...steps: Update<Error, State, any>[]): Batch<Error, State, void>;
batch(steps: Update<Error, State, any>[]): Batch<Error, State, void>;
concat(...steps: Update<State, any>[]): Concat<State, void>;
concat(steps: Update<State, any>[]): Concat<State, void>;
concat(...steps: Update<Error, State, any>[]): Concat<Error, State, void>;
concat(steps: Update<Error, State, any>[]): Concat<Error, State, void>;
of<A>(value: A): Pure<State,A>;
patch(patch: Partial<State>, callback?: () => void): Patch<State, void>;
modify(proj: (x: State) => State, callback?: () => void): Modify<State, void>;
effect<Error, Success>(eff: Eff<Error, Success>): Effect<State, Either<Error, Success>>;
get: Get<State, State>;
of<A>(value: A): Pure<Error, State, A>;
patch(patch: Partial<State>, callback?: () => void): Patch<Error, State, void>;
modify(proj: (x: State) => State, callback?: () => void): Modify<Error, State, void>;
effect<Error, Success>(eff: Eff<Error, Success>): Effect<Error, State, Success>;
get: Get<Error, State, State>;
}
export function bind<State>() {
return Update as any as BoundStatics<State>;
export function bind<Error, State>() {
return Update as any as BoundStatics<Error, State>;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment