UNPKG

11.8 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var xbrief = require('xbrief');
6var veho = require('veho');
7var crostab = require('crostab');
8var borel = require('borel');
9var hatsuMatrix = require('hatsu-matrix');
10
11function _defineProperty(obj, key, value) {
12 if (key in obj) {
13 Object.defineProperty(obj, key, {
14 value: value,
15 enumerable: true,
16 configurable: true,
17 writable: true
18 });
19 } else {
20 obj[key] = value;
21 }
22
23 return obj;
24}
25
26const _d_2 = '2-digit',
27 _num = 'numeric';
28const confDate = {
29 year: _d_2,
30 month: _d_2,
31 day: _d_2
32},
33 confTime = {
34 hour: _num,
35 minute: _num,
36 second: _num,
37 hour12: false
38};
39class Fm {}
40
41_defineProperty(Fm, "Day", new Intl.DateTimeFormat(undefined, confDate));
42
43_defineProperty(Fm, "Time", new Intl.DateTimeFormat(undefined, confTime));
44
45_defineProperty(Fm, "DayTime", new Intl.DateTimeFormat(undefined, { ...confDate,
46 ...confTime
47}));
48
49const padMilli = ms => {
50 ms = '' + ms;
51 return ms.length > 2 ? ms : ('00' + ms).slice(-3);
52};
53
54const {
55 Time
56} = Fm;
57const format = Time.format.bind(Time);
58class ETA {
59 constructor() {
60 this.t = new Date();
61 }
62
63 ini(msg = '') {
64 return `[${format(this.t)}] [Ini 0ms] ${msg}`;
65 }
66
67 split() {
68 const cur = new Date(),
69 df = cur - this.t;
70 this.t = cur;
71 return df;
72 }
73
74 lap(msg = '') {
75 return `[${format(this.t)}] [Lap ${this.split()}ms] ${msg}`;
76 }
77
78 end(msg = '') {
79 return `[${format(this.t)}] [End ${this.split()}ms] ${msg}`;
80 }
81
82} // split: another approach
83// ([this.f, this.t] = [new Date(), this.f])
84// return this.f - this.t
85
86class GP {
87 /**
88 * hh:mm:ss
89 * @param {Date} [date=new Date()]
90 * @returns {string}
91 */
92 static roughly(date = new Date()) {
93 return Fm.Time.format(date);
94 }
95 /**
96 * hh:mm:ss.mmm
97 * @param {Date} date
98 * @returns {string}
99 */
100
101
102 static time(date = new Date()) {
103 return `${Fm.Time.format(date)}.${padMilli(date.getMilliseconds())}`;
104 }
105
106 static vec(date = new Date()) {
107 return [date.getFullYear(), date.getMonth() + 1, date.getDate()];
108 }
109
110 static y4md(date = new Date(), de = '-') {
111 return [String(date.getFullYear()).padStart(4, '0'), String(date.getMonth() + 1).padStart(2, '0'), //Months are zero based
112 String(date.getDate()).padStart(2, '0')].join(de);
113 }
114
115 static mdy(date = new Date()) {
116 return Fm.Day.format(date);
117 }
118
119 static dateTime(date = new Date()) {
120 return Fm.DayTime.format(date);
121 }
122 /**
123 * Return string of current time.
124 * Format: hh:mm:ss
125 * @return {string}
126 */
127
128
129 static roughlyNow() {
130 return Fm.Time.format(new Date());
131 }
132 /**
133 * Return string of current time with 3-digit milliseconds.
134 * Format: hh:mm:ss.mmm
135 * @return {string}
136 */
137
138
139 static now() {
140 let d = new Date();
141 return `${Fm.Time.format(d)}.${padMilli(d.getMilliseconds())}`;
142 }
143 /**
144 *
145 * @returns {number}
146 */
147
148
149 static year() {
150 return new Date().getFullYear();
151 }
152 /**
153 * Return current date array in [Y,M,D] order.
154 * @returns {*[]}
155 */
156
157
158 static todayVec() {
159 const td = new Date(); //Months are zero based
160
161 return [td.getFullYear(), td.getMonth() + 1, td.getDate()];
162 }
163 /**
164 * Return current date in YYYY-MM-DD format, the delimiter '-' can be replaced by setting parameter 'de'
165 * @param {string} [de='-'] - delimiter
166 * @returns {string}
167 */
168
169
170 static today(de = '-') {
171 const td = new Date();
172 return [String(td.getFullYear()).padStart(4, '0'), String(td.getMonth() + 1).padStart(2, '0'), //Months are zero based
173 String(td.getDate()).padStart(2, '0')].join(de);
174 }
175 /**
176 * Return current date in MM/DD/YY format.
177 * Format: mm/dd/yy
178 * @return {string}
179 */
180
181
182 static todayMDY() {
183 return Fm.Day.format(new Date());
184 }
185 /**
186 * Return string of current date with time.
187 * Format: mm/dd/yy, hh:mm:ss
188 * @return {string}
189 */
190
191
192 static present() {
193 return Fm.DayTime.format(new Date());
194 }
195
196}
197
198const _reh = (r, func, params) => {
199 for (--r; r > 0; r--) func.apply(null, params);
200
201 return func.apply(null, params);
202}; // const _rehRest = (repeat, func, ...params) => {
203// for (let i = --repeat; !!i; --i) func.call(null, ...params)
204// return func.call(null, ...params)
205// }
206
207
208class Chrono {
209 /**
210 *
211 * @param {number} repeat
212 * @param {function} func
213 * @param {...*[]} [params]
214 * @return {*}
215 */
216 static rehearsalRest(repeat, func, ...params) {
217 for (--repeat; repeat > 0; repeat--) func.call(null, ...params);
218
219 return func.call(null, ...params);
220 }
221 /**
222 *
223 * @param {number} repeat
224 * @param {function} func
225 * @param {...*[]} [params]
226 * @return {*}
227 */
228
229
230 static rehearsalArgs(repeat, func, params) {
231 for (--repeat; repeat > 0; repeat--) func.call(null, params);
232
233 return func.call(null, params);
234 }
235 /**
236 * Cross by repeatList and functions.
237 * Each function contains no parameter.
238 * @param {number[]} repeatList
239 * @param {Object<string,function>} funcList
240 * @param {*[]} [params]
241 * @returns {CrosTab}
242 */
243
244
245 static crossByRepeatsAndFuncs({
246 repeatList,
247 funcList,
248 params = []
249 }) {
250 const eta = new ETA();
251 const [side, banner] = [repeatList, Object.keys(funcList)];
252 const [ht, wd] = [side.length, banner.length];
253 const [lapseX, valueRow] = [veho.Mx.ini(ht, wd, (i, j) => 0), veho.Ar.ini(wd, () => null)];
254 eta.ini();
255
256 for (let [x, repeat] of Object.entries(repeatList)) {
257 var _ref, _Object$keys;
258
259 _ref = `[${GP.now()}] [${x}] (${repeat}): repeat for each of [${(_Object$keys = Object.keys(funcList), xbrief.ArrX.hBrief(_Object$keys))}]`, console.log(_ref);
260 eta.split();
261
262 for (let [y, func] of Object.values(funcList).entries()) {
263 valueRow[y] = _reh(repeat, func, params);
264 lapseX[x][y] = eta.split();
265 }
266 }
267
268 return new crostab.CrosTab(side, banner, lapseX, 'repeat #').unshiftRow('result', valueRow);
269 }
270 /**
271 * Cross by paramsList and functions, under certain repeat.
272 * Each function receives the same list of paramsList.
273 * @param {number} repeat
274 * @param {Object<string,*[]>} paramsList - each value is an array of parameters.
275 * @param {Object<string,function>} funcList
276 * @param {{showAverage:boolean,showParamsValues:boolean}} [config]
277 * @returns {{lapse:CrosTab,result:CrosTab}}
278 */
279
280
281 static strategies({
282 repeat,
283 paramsList,
284 funcList,
285 config = {
286 showAverage: true,
287 showParamsValues: false
288 }
289 }) {
290 var _lapse$columns$map$ma;
291
292 const eta = new ETA(),
293 [side, banner] = [Object.keys(paramsList), Object.keys(funcList)],
294 [ht, wd] = [side.length, banner.length],
295 [lapseX, valueX] = [veho.Mx.ini(ht, wd, (i, j) => 0), veho.Mx.ini(ht, wd, (i, j) => null)];
296 eta.ini();
297
298 for (let [x, [label, params]] of Object.entries(paramsList).entries()) {
299 var _ref2;
300
301 _ref2 = `[${GP.now()}] [${x}] (${label}) tested by each of funcs [${banner}], each repeated * ${repeat}.`, console.log(_ref2);
302 eta.split();
303
304 for (let [y, func] of Object.values(funcList).entries()) {
305 valueX[x][y] = _reh(repeat, func, params);
306 lapseX[x][y] = eta.split();
307 }
308 }
309
310 let [lapse, result] = [crostab.CrosTab.from({
311 side,
312 banner,
313 matrix: lapseX,
314 title: 'parameter'
315 }).clone(), crostab.CrosTab.from({
316 side,
317 banner,
318 matrix: valueX,
319 title: 'parameter'
320 }).clone()];
321 if (config.showAverage) lapse.unshiftRow('avg', (_lapse$columns$map$ma = lapse.columns.map(borel.Stat.avg).map(it => it.toFixed()), hatsuMatrix.Visual.vector(_lapse$columns$map$ma)));
322 if (config.showParamsValues) result.unshiftCol('input', Object.values(paramsList));
323 return {
324 lapse,
325 result
326 };
327 }
328
329}
330
331class Dawdle {
332 static linger(ms, fn, ...args) {
333 return new Promise((pass, veto) => {
334 let st = false,
335 rs;
336 Promise.resolve(fn.apply(null, args)).then(x => st++ ? pass(x) : rs = x, veto);
337 Promise.resolve(Dawdle.timeout(ms)).then(_ => {
338 if (st++) pass(rs);
339 }, veto);
340 });
341 }
342
343 static timeout(ms) {
344 return new Promise(pass => setTimeout(pass, ms));
345 }
346
347}
348
349const monthCap = (m, lp) => m !== 0b10 ? 30 + m % 0b10 ^ m >= 0x8 : 28 + lp;
350
351const leapYear = y => y % 4 ? false : y % 100 ? true : !(y % 400);
352
353const nextMonth = dt => {
354 dt.m += 1;
355
356 if (dt.m > 12) {
357 dt.y += 1;
358 dt.m = 1;
359 dt.lp = leapYear(dt.y);
360 }
361
362 dt.cap = monthCap(dt.m, dt.lp);
363 return dt;
364};
365const prevMonth = dt => {
366 dt.m -= 1;
367
368 if (dt.m < 1) {
369 dt.y -= 1;
370 dt.m = 12;
371 dt.lp = leapYear(dt.y);
372 }
373
374 dt.cap = monthCap(dt.m, dt.lp);
375 return dt;
376};
377const yearForth = dt => {
378 let {
379 y,
380 m,
381 d
382 } = dt;
383
384 while (d >= 365) {
385 d -= 365;
386 if (m <= 2 && leapYear(y++) || m > 2 && leapYear(++y)) d--;
387 }
388
389 const lp = leapYear(y);
390 return {
391 y,
392 m,
393 d,
394 lp,
395 cap: monthCap(m, lp)
396 };
397};
398const yearBack = dt => {
399 let {
400 y,
401 m,
402 d
403 } = dt;
404
405 while (d <= -365) {
406 d += 365;
407 if (m <= 2 && leapYear(--y) || m > 2 && leapYear(y--)) d++;
408 }
409
410 const lp = leapYear(y);
411 return {
412 y,
413 m,
414 d,
415 lp,
416 cap: monthCap(m, lp)
417 };
418};
419const daysForth = dt => {
420 while (dt.d > dt.cap) {
421 var _dt;
422
423 dt.d -= dt.cap;
424 _dt = dt, nextMonth(_dt);
425 }
426
427 return dt;
428};
429const daysBack = dt => {
430 dt.cap = 0;
431
432 while (dt.d < dt.cap) {
433 var _dt2;
434
435 _dt2 = dt, prevMonth(_dt2);
436 dt.d += dt.cap;
437 }
438
439 return daysForth(dt);
440};
441
442const endOfMonth = (y, m) => monthCap(m, leapYear(y));
443const calibre = (y, m, d, hi) => {
444 if (d >= hi) return [y, m, endOfMonth(y, m)];
445 if (d >= 28) return [y, m, Math.min(d, endOfMonth(y, m))];
446 return [y, m, d];
447};
448
449const pad0 = (n, l) => {
450 n = '' + n;
451
452 while (n.length < l) n = '0' + n;
453
454 return n;
455};
456
457const joinY4MD = (y, m, d, l = '-') => `${+y < 1000 ? pad0(+y, 4) : +y}${l}${+m < 10 ? pad0(+m, 2) : +m}${l}${+d < 10 ? pad0(+d, 2) : +d}`;
458
459const ymdToInt = ([y, m, d]) => ((y & 0xffff) << 9) + ((m & 0xf) << 5) + ((d & 0x1f) << 0);
460
461class Y4MD {
462 static now() {
463 return Y4MD.fromDate(new Date());
464 }
465
466 static fromDate(date = new Date()) {
467 return [date.getFullYear(), date.getMonth() + 1, date.getDate()];
468 }
469
470 static toDate(ymd) {
471 return new Date(ymd[0], ymd[1] - 1, ymd[2]);
472 }
473
474 static fromTx(tx) {
475 return [+tx.slice(0, 4), +tx.slice(5, 7), +tx.slice(8, 10)];
476 }
477
478 static toTx(ymd, de = '-') {
479 return joinY4MD(ymd[0], ymd[1], ymd[2], de);
480 }
481
482 static belongTo(ymd, lo, hi) {
483 const int = ymdToInt(ymd);
484 return ymdToInt(lo) <= int && int <= ymdToInt(hi);
485 }
486
487 static addD([y, m, d], days) {
488 let lp = leapYear(y),
489
490 /**
491 *
492 * @type {{y: number, m: number,d: number, lp: boolean, cap: number }}
493 */
494 dt = {
495 y,
496 m,
497 d: d + days,
498 lp,
499 cap: monthCap(m, lp)
500 };
501 if (dt.d - 365 > 0) dt = yearForth(dt);
502 if (dt.d + 365 < 0) dt = yearBack(dt);
503 dt = dt.d >= 0 ? daysForth(dt) : daysBack(dt);
504 return [dt.y, dt.m, dt.d];
505 }
506
507 static addM([y, m, d], months) {
508 let eom = endOfMonth(y, m);
509 let ym = y * 12 + m + months;
510 y = ~~(ym / 12);
511 m = ym % 12;
512
513 if (m < 1) {
514 y--;
515 m = 12;
516 }
517
518 return calibre(y, m, d, eom);
519 }
520
521 static addQ([y, m, d], quarters) {
522 return Y4MD.addM([y, m, d], quarters * 3);
523 }
524
525 static addY([y, m, d], years) {
526 return calibre(y + years, m, d, endOfMonth(y, m));
527 }
528
529 static seasonLoHi([y, m]) {
530 let hi = ~~((m - 1) / 3 + 1) * 3;
531 return [[y, hi - 2, 1], [y, hi, endOfMonth(y, hi)]];
532 }
533
534 static monthLoHi([y, m]) {
535 return [[y, m, 1], [y, m, endOfMonth(y, m)]];
536 }
537
538}
539
540exports.Chrono = Chrono;
541exports.Dawdle = Dawdle;
542exports.ETA = ETA;
543exports.GP = GP;
544exports.Y4MD = Y4MD;