Skip to content

Commit

Permalink
Merge pull request #1 from matt-mcmahon/working
Browse files Browse the repository at this point in the history
Prepare for Deno-First
  • Loading branch information
matt-mcmahon authored Oct 9, 2020
2 parents f6dbef6 + 099c2b5 commit 089db67
Show file tree
Hide file tree
Showing 389 changed files with 788 additions and 3,943 deletions.
5 changes: 5 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@
node_modules
# don't lint build output (make sure it's set to your correct build folder name)
dist
build
# don't lint nyc coverage output
coverage
# ignore own configuration
.eslintrc.js
# don't lint examples
examples
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module.exports = {
"no-obj-calls": "error",
"no-octal": "error",
"no-prototype-builtins": "error",
"@typescript-eslint/no-redeclare": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-setter-return": "error",
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": ["combinator", "iife", "uncurry", "unreducable"]
"cSpell.words": ["combinator", "iife", "uncurry", "unreducable"],
"eslint.lintTask.enable": true
}
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ Further, every exported function has an even simpler, [haskell-style][3], `<func

## Rational

Some of the challenges I've encountered learning [Functional Programming][6] in JavaScript
are obtuse function signatures and implementations that are hard to debug.
Some of the challenges I've encountered learning [Functional Programming][6] in JavaScript are obtuse function signatures and implementations that are hard to debug.
This project is designed to remedy these issues.

The goal is to provide simple, debuggable, functional programming building blocks that anyone can use while learning FP concepts.
Implementations should be largely stand-alone, easy to read, and easy to debug.
As a consequence, many of the included functions will contain duplicate and unoptimized code,
but easier reading and reduced cognitive load should make the trade-off worthwhile.
As a consequence, many of the included functions will contain duplicate and unoptimized code, but easier reading and reduced cognitive load should make the trade-off worthwhile.

This library is **not** meant to replace well-tested and engineered libraries like [lodash/fp][7] or [Ramda][8].
Instead, it's primarily meant to be a learning aid.
Expand All @@ -28,8 +26,7 @@ When you're ready, you can easily replace the _Functional_ dependency with _Ramd
## Credits

To keep this library simple and easily debuggable, I'll occasionally copy code from projects that have a compatible license into this project (instead of importing it as a dependency).
When this is done, I'll include the original license with the source-code for that module,
and (with permission) I'll give credit both here and in _package.json_'s `contributor` field.
When this is done, I'll include the original license with the source-code for that module, and (with permission) I'll give credit both here and in _package.json_'s `contributor` field.
Programming is hard work, and I can't thank the open-source community enough for the enormity of their multitudinous efforts!

## Special Thanks To:
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions dist/app/functions/F.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const F: (...ignored: unknown[]) => false;
4 changes: 4 additions & 0 deletions dist/app/functions/F.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.F = void 0;
exports.F = (...ignored) => false;
1 change: 1 addition & 0 deletions dist/app/functions/T.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const T: (...ignored: unknown[]) => true;
4 changes: 4 additions & 0 deletions dist/app/functions/T.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.T = void 0;
exports.T = (...ignored) => true;
1 change: 1 addition & 0 deletions dist/app/functions/always.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const always: <A>(a: A) => (...bs: unknown[]) => A;
4 changes: 4 additions & 0 deletions dist/app/functions/always.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.always = void 0;
exports.always = (a) => (...bs) => a;
3 changes: 3 additions & 0 deletions dist/app/functions/assoc.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export declare const assoc: <K extends string | number | symbol>(k: K) => <B>(b: B) => <A>(a: A) => A | {
K: B;
};
5 changes: 5 additions & 0 deletions dist/app/functions/assoc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assoc = void 0;
const clone_1 = require("./clone");
exports.assoc = (k) => (b) => (a) => Object.assign(clone_1.clone(a), { [k]: b });
1 change: 1 addition & 0 deletions dist/app/functions/bind.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const bind: <M extends CallableFunction>(m: M) => (b: ThisParameterType<M>) => OmitThisParameter<M>;
4 changes: 4 additions & 0 deletions dist/app/functions/bind.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bind = void 0;
exports.bind = (m) => (b) => m.bind(b);
1 change: 1 addition & 0 deletions dist/app/functions/blackbird.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const blackbird: <BS extends any[], C>(converging: (...bs: BS) => C) => <A>(...parts: ((a: A) => unknown)[]) => (a: A) => C;
7 changes: 7 additions & 0 deletions dist/app/functions/blackbird.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.blackbird = void 0;
exports.blackbird = (converging) => (...parts) => (a) => {
const bs = parts.map((part) => part(a));
return converging(...bs);
};
1 change: 1 addition & 0 deletions dist/app/functions/both.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const both: <A, B>(first: (a: A) => B) => <C>(second: (a: A) => C) => (a: A) => B | C;
4 changes: 4 additions & 0 deletions dist/app/functions/both.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.both = void 0;
exports.both = (first) => (second) => (a) => first(a) && second(a);
1 change: 1 addition & 0 deletions dist/app/functions/cap.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const cap: (word: string) => string;
6 changes: 0 additions & 6 deletions dist/functions/cap.js → dist/app/functions/cap.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cap = void 0;
/**
* ```
* cap :: s => s
* ```
* @param {string} word word we want to capitalize
*/
exports.cap = (word) => typeof word === "string" && word.length > 0
? word[0].toLocaleUpperCase() + word.substr(1)
: word;
1 change: 1 addition & 0 deletions dist/app/functions/clone.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function clone<A>(a: A): A;
23 changes: 8 additions & 15 deletions dist/functions/clone.js → dist/app/functions/clone.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use strict";
/* eslint-disable @typescript-eslint/ban-types -- WeakMap needs an object type */
Object.defineProperty(exports, "__esModule", { value: true });
exports.clone = void 0;
const functions_1 = require("../functions");
const isArray_1 = require("./isArray");
const isDate_1 = require("./isDate");
const isObject_1 = require("./isObject");
const isDefined_1 = require("./isDefined");
function cloneObject(a, map) {
if (map.has(a)) {
return map.get(a);
Expand Down Expand Up @@ -33,26 +35,17 @@ function cloneArray(a, map) {
}
}
function cloneUnknown(a, map) {
const t = functions_1.isDefined(a)
? functions_1.isDate(a)
const t = isDefined_1.isDefined(a)
? isDate_1.isDate(a)
? cloneDate(a)
: functions_1.isArray(a)
: isArray_1.isArray(a)
? cloneArray(a, map)
: functions_1.isObject(a)
: isObject_1.isObject(a)
? cloneObject(a, map)
: a
: a;
return t;
}
/**
* ```
* clone :: a => a
* ```
* @export
* @template A
* @param {A} a
* @returns {A}
*/
function clone(a) {
const map = new WeakMap();
return cloneUnknown(a, map);
Expand Down
1 change: 1 addition & 0 deletions dist/app/functions/complement.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const complement: <A>(predicate: (a: A) => boolean) => (a: A) => boolean;
4 changes: 4 additions & 0 deletions dist/app/functions/complement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.complement = void 0;
exports.complement = (predicate) => (a) => !predicate(a);
9 changes: 9 additions & 0 deletions dist/app/functions/compose.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Last } from "../types";
export declare type Compose<B, A> = {
(b: B): A;
call(a: A): B;
from<C>(f: (c: C) => B): Compose<C, A>;
};
export declare const compose: (<FS extends ((x: any) => any)[]>(...fs: FS) => (a: Parameters<Last<FS>>[0]) => ReturnType<FS[0]>) & {
fluent: <B, A>(f: (b: B) => A) => Compose<B, A>;
};
30 changes: 30 additions & 0 deletions dist/app/functions/compose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compose = void 0;
const fluent = (f) => {
function call(b) {
return f(b);
}
const p = Object.assign(call.bind(null), {
from: (f) => {
return after(p, f);
},
call,
});
return p;
};
const after = (next, f) => {
function call(c) {
return next(f(c));
}
const p = Object.assign(call.bind(null), {
from: (f) => {
return after(p, f);
},
call,
});
return p;
};
exports.compose = Object.assign((...fs) => {
return (a) => fs.reduceRight((v, f) => f(v), a);
}, { fluent });
1 change: 1 addition & 0 deletions dist/app/functions/concat.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const concat: <A extends readonly unknown[]>(as: A) => <B extends readonly unknown[]>(bs: B) => [...A, ...B];
4 changes: 4 additions & 0 deletions dist/app/functions/concat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.concat = void 0;
exports.concat = (as) => (bs) => [...as, ...bs];
1 change: 1 addition & 0 deletions dist/app/functions/curry.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const curry: <F extends Function>(f: F) => Function;
5 changes: 5 additions & 0 deletions dist/app/functions/curry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.curry = void 0;
const curryN_1 = require("./curryN");
exports.curry = (f) => curryN_1.curryN(f.length)(f);
1 change: 1 addition & 0 deletions dist/app/functions/curryN.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const curryN: (n: number) => <F extends Function>(f: F) => Function;
10 changes: 0 additions & 10 deletions dist/functions/curryN.js → dist/app/functions/curryN.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,4 @@ const gather = (n, f, previous = []) => {
});
return curried;
};
/**
* ```
* curryN :: n => ((a¹, a², ..., aⁿ) => b) => a¹ => a²... => aⁿ => b
* ```
* -----------------------------------------------------------------------------
* Converts a function that accepts an arity, __n__, number of arguments into a
* series of _Unary_ functions that produce the same final value.
*
* @todo add support for Variadic Tuples in TypeScript 4
*/
exports.curryN = (n) => (f) => gather(n, f);
1 change: 1 addition & 0 deletions dist/app/functions/defaultTo.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const defaultTo: <A>(a: A) => <B>(b: B) => A | B;
6 changes: 6 additions & 0 deletions dist/app/functions/defaultTo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultTo = void 0;
const isDefined_1 = require("./isDefined");
const isNaN_1 = require("./isNaN");
exports.defaultTo = (a) => (b) => isNaN_1.isNaN(b) ? a : isDefined_1.isDefined(b) ? b : a;
1 change: 1 addition & 0 deletions dist/app/functions/either.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const either: <A, B>(mapAB: (a: A) => B) => <C>(mapAC: (a: A) => C) => (a: A) => B | C;
4 changes: 4 additions & 0 deletions dist/app/functions/either.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.either = void 0;
exports.either = (mapAB) => (mapAC) => (a) => mapAB(a) || mapAC(a);
1 change: 1 addition & 0 deletions dist/app/functions/equals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const equals: (a: unknown) => (b: unknown) => boolean;
4 changes: 4 additions & 0 deletions dist/app/functions/equals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.equals = void 0;
exports.equals = (a) => (b) => a === b;
1 change: 1 addition & 0 deletions dist/app/functions/filter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const filter: <A>(p: (a: A) => boolean) => (as: A[]) => A[];
4 changes: 4 additions & 0 deletions dist/app/functions/filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.filter = void 0;
exports.filter = (p) => (as) => as.filter(p);
1 change: 1 addition & 0 deletions dist/app/functions/has.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const has: <K extends string | number | symbol>(k: K) => (a: unknown) => a is { [P in K]: unknown; };
4 changes: 4 additions & 0 deletions dist/app/functions/has.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.has = void 0;
exports.has = (k) => (a) => Object.prototype.hasOwnProperty.call(a, k);
1 change: 1 addition & 0 deletions dist/app/functions/head.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const head: <A>(as: A[]) => A;
4 changes: 4 additions & 0 deletions dist/app/functions/head.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.head = void 0;
exports.head = (as) => as[0];
1 change: 1 addition & 0 deletions dist/app/functions/identity.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const identity: <A>(a: A) => A;
4 changes: 4 additions & 0 deletions dist/app/functions/identity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.identity = void 0;
exports.identity = (a) => a;
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions dist/app/functions/iife.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const iife: <AS extends unknown[], B>(f: (...as: AS) => B, ...as: AS) => B;
4 changes: 4 additions & 0 deletions dist/app/functions/iife.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.iife = void 0;
exports.iife = (f, ...as) => f(...as);
1 change: 1 addition & 0 deletions dist/app/functions/init.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const init: <A>(as: A[]) => A[];
4 changes: 4 additions & 0 deletions dist/app/functions/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = void 0;
exports.init = (as) => as.slice(0, as.length - 1);
1 change: 1 addition & 0 deletions dist/app/functions/invoker.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const invoker: <K extends string | number | symbol>(k: K) => <AS extends unknown[]>(...as: AS) => <B>(c: { [_ in K]: (...as: AS) => B; }) => B;
4 changes: 4 additions & 0 deletions dist/app/functions/invoker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.invoker = void 0;
exports.invoker = (k) => (...as) => (c) => c[k](...as);
1 change: 1 addition & 0 deletions dist/app/functions/isArray.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isArray: (arg: any) => arg is any[];
4 changes: 4 additions & 0 deletions dist/app/functions/isArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isArray = void 0;
exports.isArray = Array.isArray;
1 change: 1 addition & 0 deletions dist/app/functions/isDate.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isDate: (a: unknown) => a is Date;
4 changes: 4 additions & 0 deletions dist/app/functions/isDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDate = void 0;
exports.isDate = (a) => a instanceof Date;
1 change: 1 addition & 0 deletions dist/app/functions/isDefined.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isDefined: <A>(a: A) => a is Exclude<A, null> & Exclude<A, undefined>;
4 changes: 4 additions & 0 deletions dist/app/functions/isDefined.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDefined = void 0;
exports.isDefined = (a) => a != null;
1 change: 1 addition & 0 deletions dist/app/functions/isEmpty.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isEmpty: (a: unknown) => boolean;
6 changes: 6 additions & 0 deletions dist/app/functions/isEmpty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isEmpty = void 0;
exports.isEmpty = (a) => (Array.isArray(a) && a.length === 0) ||
(typeof a === "string" && a.length === 0) ||
(typeof a === "object" && a !== null && Object.keys(a).length === 0);
1 change: 1 addition & 0 deletions dist/app/functions/isFunction.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isFunction: (a: unknown) => a is Function;
4 changes: 4 additions & 0 deletions dist/app/functions/isFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isFunction = void 0;
exports.isFunction = (a) => typeof a === "function";
1 change: 1 addition & 0 deletions dist/app/functions/isNaN.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isNaN: (a: unknown) => a is number;
4 changes: 4 additions & 0 deletions dist/app/functions/isNaN.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNaN = void 0;
exports.isNaN = (a) => Number.isNaN(a);
1 change: 1 addition & 0 deletions dist/app/functions/isNil.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isNil: (a: unknown) => a is null | undefined;
4 changes: 4 additions & 0 deletions dist/app/functions/isNil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNil = void 0;
exports.isNil = (a) => a === null || a === undefined;
1 change: 1 addition & 0 deletions dist/app/functions/isNumber.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isNumber: (a: unknown) => a is number;
4 changes: 4 additions & 0 deletions dist/app/functions/isNumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNumber = void 0;
exports.isNumber = (a) => typeof a === "number";
1 change: 1 addition & 0 deletions dist/app/functions/isObject.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isObject: (a: unknown) => a is object;
4 changes: 4 additions & 0 deletions dist/app/functions/isObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObject = void 0;
exports.isObject = (a) => typeof a === "object";
1 change: 1 addition & 0 deletions dist/app/functions/isString.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const isString: (a: unknown) => a is string;
4 changes: 4 additions & 0 deletions dist/app/functions/isString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isString = void 0;
exports.isString = (a) => typeof a === "string";
1 change: 1 addition & 0 deletions dist/app/functions/join.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const join: (a: string | undefined) => <A>(bs: A[]) => string;
Loading

0 comments on commit 089db67

Please sign in to comment.