UNPKG

@tangential/core

Version:

Core types and support code for Tangential

1,157 lines (1,126 loc) 42.9 kB
import * as i0 from '@angular/core'; import { EventEmitter, Injectable, Optional } from '@angular/core'; import { share, filter, map } from 'rxjs/operators'; import { filter as filter$1 } from 'rxjs'; class SelectionEntry { constructor(value, selected = false, disabled = false) { this.value = value; this.selected = selected; this.disabled = disabled; } } class SelectionList { constructor(initialValues = [], selectAll = false, keyField = '$key') { this.keyField = keyField; this.entries = initialValues.map((v) => { return new SelectionEntry(v, selectAll); }); } asIndexMap() { const indices = {}; this.entries.forEach((entry, index) => { indices[entry.value[this.keyField]] = index; }); return indices; } select(values) { const map = this.asIndexMap(); values.forEach((value) => { const index = map[value[this.keyField]]; if (index || index === 0) { this.entries[index].selected = true; } }); } disable(values) { const map = this.asIndexMap(); values.forEach((value) => { const index = map[value[this.keyField]]; if (index || index === 0) { this.entries[index].disabled = true; } }); } } class ArrayUtils { static peek(ary) { let v = undefined; if (ary && ary.length) { v = ary[ary.length - 1]; } return v; } } class Guard { static isString(value) { return typeof value === 'string'; } } class CodedError extends Error { constructor(message, code) { super(message); this.code = code; } } class ObjMapUtil { static fromKeyedEntityArray(values, keyField = '$key') { values = values || []; const m = {}; for (let i = 0; i < values.length; i++) { m[values[i][keyField]] = values[i]; } return m; } static toArray(map) { return Object.keys(map).map((key) => { return map[key]; }); } static toKeyedEntityArray(map, keyField = '$key') { return Object.keys(map).map((key) => { const keyObj = {}; // semicolon actually required here. keyObj[keyField] = key; return Object.assign({}, map[key], keyObj); }); } static toTruthMap(map) { const result = {}; Object.keys(map).forEach((key) => { result[key] = true; }); return result; } static addAll(map, mapB, noOverwrite = false) { map = map || {}; mapB = mapB || {}; Object.keys(mapB).forEach((key) => { if (noOverwrite && map[key] !== undefined) { throw new Error(`Key already exists on map, cannot replace: ${key}.`); } map[key] = mapB[key]; }); return map; } static removeAll(map, mapB) { Object.keys(mapB).forEach((key) => { if (map[key] !== undefined) { delete map[key]; } }); } /** * Remove the child fields from the provided map. * @param map * @param fields {string[]} * @returns {ObjMap<V>} */ static deleteValueFields(map, fields = ['$key']) { map = map || {}; fields.forEach((fieldKey) => { Object.keys(map).forEach((key) => { delete map[key][fieldKey]; }); }); return map; } } const ResolveVoid = undefined; class ObjectUtil { /** * Null safe version of Object.keys. * @param map * @returns {string[]} The keys for the map, or an empty array if the argument provided is falsy. */ static keys(map) { return Object.keys(map || {}); } /** * Provide a map of keys such that 'map[key]' provides a literal true value if the key is present, even if the value * on the source map is falsy. */ static toTruthMap(ary) { const map = {}; ary.forEach(value => map[value] = true); return map; } /** * Expand the map into an array of key-value pairs. * @param {ObjMap<T extends object>} map * @returns MapEntry<T> */ static entries(map) { const ret = Object.keys(map || {}).map((key) => { return { key: key, value: map[key] }; }); return ret; } /** * Provide the values of the map. * @param {ObjMap<T>} map * @returns MapEntry<T> */ static values(map) { return Object.keys(map || {}).map((key) => { return map[key]; }); } static isObject(value) { return (typeof value === 'object' || value.constructor === Object); } static isFunction(value) { return (typeof value === 'function' || value instanceof Function); } static isNullOrDefined(value) { return value === null || value === undefined; } static exists(value) { return value !== null && value !== undefined; } static assignDeep(target, ...sources) { target = target || {}; const L = sources.length; for (let i = 0; i < L; i++) { const source = sources[i] || {}; Object.keys(source).forEach(key => { const value = source[key]; if (value && ObjectUtil.isObject(value)) { target[key] = ObjectUtil.assignDeep({}, target[key] || {}, value); } else { target[key] = value; } }); } return target; } static removeNullish(obj) { const cleanObj = {}; Object.keys(obj).forEach((key) => { const v = obj[key]; if (v !== null && v !== undefined) { cleanObj[key] = v; } }); return cleanObj; } } const cleanFirebaseMap = function (firebaseList, deep) { const result = {}; Object.keys(firebaseList).forEach((key) => { if (key[0] !== '$') { if (deep && firebaseList[key] instanceof Object) { result[key] = cleanFirebaseMap(firebaseList[key], true); } else { result[key] = firebaseList[key]; } } }); return result; }; const pathExists = (object, path) => { const parts = path.split('\.'); let exists = true; let obj = object; for (let i = 0; i < parts.length; i++) { obj = obj[parts[i]]; if (obj === undefined) { exists = false; break; } } return exists; }; const ensureExists = (object, path, value = true) => { const parts = path.split('\.'); let obj = object; for (let i = 0; i < parts.length - 1; i++) { const key = parts[i]; if (obj[key] === undefined) { obj[key] = {}; } obj = obj[key]; } const lastKey = parts[parts.length - 1]; if (obj[lastKey] === undefined) { obj[lastKey] = value; } return obj[lastKey]; }; const removeIfExists = (object, path) => { const parts = path.split('\.'); let obj = object; let existed = true; for (let i = 0; i < parts.length - 1; i++) { obj = obj[parts[i]]; if (obj === undefined) { existed = false; break; } } if (existed) { const lastKey = parts[parts.length - 1]; existed = obj[lastKey] !== undefined; if (existed) { delete obj[lastKey]; } } return existed; }; const safe = (fn) => { try { return fn(); } catch (e) { return null; } }; const eachKey = (objMap, fn) => { Object.keys(objMap).forEach((key) => { fn(objMap[key], key); }); }; class JsonUtil { static diff(left, right) { const diff = {}; let keys = ObjectUtil.keys(left).concat(ObjectUtil.keys(right)); keys = ObjectUtil.keys(ObjectUtil.toTruthMap(keys)); keys.forEach(key => { const leftVal = left[key]; const rightVal = right[key]; if (!JsonUtil.areEqual(leftVal, rightVal)) { diff[key] = true; } }); return diff; } static areEqual(left, right) { let areEqual; if (left === right) { areEqual = true; } else if (!left || !right) { areEqual = false; } else if (ObjectUtil.isObject(left)) { if (!ObjectUtil.isObject(right)) { areEqual = false; } else { areEqual = ObjectUtil.keys(JsonUtil.diff(left, right)).length === 0; } } return areEqual || false; } static applyJsonToInstance(instance, json) { const model = instance.getModel(); json = json || {}; ObjectUtil.keys(model).forEach((key) => { instance[key] = this.determineValue(json[key], model[key]); }); } static determineValue(jsonValue, defaultValue) { let value = null; if (ObjectUtil.isNullOrDefined(jsonValue)) { value = defaultValue; } else if (ObjectUtil.isObject(jsonValue)) { value = ObjectUtil.assignDeep({}, defaultValue, jsonValue); } else { value = jsonValue; } return value; } static instanceToJson(instance, withHiddenFields) { const model = instance.getModel(); const json = {}; ObjectUtil.keys(model).forEach((key) => { if (withHiddenFields || JsonUtil.isLegalFirebaseKey(key)) { const value = instance[key]; json[key] = value; if (value) { if (ObjectUtil.isFunction(value['toJson'])) { json[key] = value.toJson(withHiddenFields); } else if (ObjectUtil.isObject(value)) { json[key] = JsonUtil.mapToJson(value, withHiddenFields || false); } } } }); return json; } static mapToJson(map, withHiddenFields) { const json = {}; // @ts-ignore Typescript is confused by the return type of ObjectUtil.entries. ObjectUtil.entries(map).forEach((entry) => { let v = entry.value; if (v && v['toJson'] && ObjectUtil.isFunction(v['toJson'])) { v = v.toJson(withHiddenFields); } json[entry.key] = v; }); return json; } static keyedArrayToJsonMap(array, withHiddenFields, keyField = '$key') { const json = {}; array.forEach(entry => { json[entry[keyField]] = entry.toJson(withHiddenFields); }); return json; } /** * @param obj * @returns {T} * @deprecated See FireBlanket.util.removeIllegalKey */ static removeIllegalFirebaseKeys(obj) { const cleanObj = {}; Object.keys(obj).forEach((key) => { const v = obj[key]; if (JsonUtil.isLegalFirebaseKey(v)) { cleanObj[key] = v; } }); return cleanObj; } /** * @param key * @returns {boolean} * @deprecated See FireBlanket.util.isLegalFirebaseKey */ static isLegalFirebaseKey(key) { return key !== null && key !== undefined && !key.startsWith('$'); } } class ReactiveUtil { static unSub(subscription) { if (subscription) { subscription.unsubscribe(); } } } class StringUtil { static firstUniqueByCounterSuffix(value, values, separatorChar = ' ') { let result = value; const map = {}; values.forEach(v => map[v] = true); let idx = 1; while (map[result]) { result = value + separatorChar + idx++; } return result; } /** * Split a string that ends with a number into its corresponding parts. Useful for name collisions, e.g. * FooValue, FooValue-1, FooValue-2 * @param value */ static withoutNumericSuffix(value) { let idx = value.length; const suffixChars = []; for (idx; idx--; idx > 0) { if (StringUtil._baseTen[value.charAt(idx)] !== true) { break; } suffixChars.unshift(value.charAt(idx)); } const suffixValue = suffixChars.length ? Number.parseInt(suffixChars.join('')) : undefined; const text = value.substring(0, idx); return { text: text.trim(), suffix: suffixValue }; } static incrementCounterSuffix(value) { let result = value; let suffixValue = 1; const suffixChars = []; let idx = value.length; for (idx; idx--; idx > 0) { if (StringUtil._baseTen[value.charAt(idx)] !== true) { break; } suffixChars.unshift(value.charAt(idx)); } if (suffixChars.length) { try { suffixValue = Number.parseInt(suffixChars.join('')); result = value.substring(0, idx + 1); } catch (e) { suffixValue = 1; } } return result + (suffixValue + 1); } } StringUtil._baseTen = [true, true, true, true, true, true, true, true, true, true]; class AppEnvironment { constructor() { this.firebase = {}; // Class is another "we'd use an interface if we could, but compiler deletes interfaces" this.name = 'dev'; this.production = false; this.suppressAds = false; } } /** * From https://gist.github.com/mikelehen/3596a30bd69384624c11, via Firebase blog at * https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html * With minor tweaks for use with TypeScript **/ /** * Fancy ID generator that creates 20-character string identifiers with the following properties: * * 1. They're based on timestamp so that they sort *after* any existing ids. * 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs. * 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly). * 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the * latter ones will sort after the former ones. We do this by using the previous random bits * but "incrementing" them by 1 (only in the case of a timestamp collision). */ // Modeled after base64 web-safe chars, but ordered by ASCII. const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'; // Timestamp of last push, used to prevent local collisions if you push twice in one ms. let lastPushTime = 0; // We generate 72-bits of randomness which get turned into 12 characters and appended to the // timestamp to prevent collisions with other clients. We store the last characters we // generated because in the event of a collision, we'll use those same characters except // "incremented" by one. const lastRandChars = []; const generatePushID = function () { let i; let now = Date.now(); const duplicateTime = (now === lastPushTime); lastPushTime = now; const timeStampChars = new Array(8); for (i = 7; i >= 0; i--) { timeStampChars[i] = PUSH_CHARS.charAt(now % 64); // NOTE: Can't use << here because javascript will convert to int and lose the upper bits. now = Math.floor(now / 64); } if (now !== 0) { throw new Error('We should have converted the entire timestamp.'); } let id = timeStampChars.join(''); if (!duplicateTime) { for (i = 0; i < 12; i++) { lastRandChars[i] = Math.floor(Math.random() * 64); } } else { // If the timestamp hasn't changed since last push, use the same random number, except incremented by 1. for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) { lastRandChars[i] = 0; } lastRandChars[i]++; } for (i = 0; i < 12; i++) { id += PUSH_CHARS.charAt(lastRandChars[i]); } if (id.length !== 20) { throw new Error('Length should be 20.'); } return id; }; const Intention = { /** * An action has been performed. For example, a user has been created, granted a permission, removed, etc. */ action: 'action', /** * A general event, typically used to communicate UI state across domains. */ event: 'event', /** * A BusMessage whose intent is to record a log message. */ log: 'log', /** * A BusMessage whose intent is to provide a message to the Visitor. It is up to the currently active UI to determine the best method * of sharing the message payload. */ notification: 'notification', /** * A BusMessage that communicates that the current Visitor has requested than an action be performed. For example, clicked a button * that is intended to result in a user being created, a permission being granted, etc. */ request: 'request', }; class BusMessage { /** @todo: 'intent' should probably be handled by static creation methods. */ constructor(source, intent, key) { this.id = generatePushID(); this.source = source; this.intent = intent || 'event'; // this should not be optional. this.key = key || '_'; } } class MessageBus { constructor() { this.bus = new EventEmitter(false); this.all = this.bus.pipe(share()); } post(message) { this.bus.next(message); } } MessageBus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); MessageBus.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: MessageBus, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); class LogMessage extends BusMessage { constructor(level, context, ...message) { super(LogMessage.SourceKey, 'log'); this.message = message; this.context = context; this.level = level; } } LogMessage.SourceKey = "LogMessage"; const spaces$1 = ' '; /** * * */ const LogLevels = { NONE: 'NONE', fatal: 'fatal', error: 'error', warn: 'warn', info: 'info', debug: 'debug', trace: 'trace' }; class LoggerConfiguration { constructor() { this.contextAsStringWidth = 30; this.includeFullContext = false; /** * For temporarily shutting of logging, use NONE, but if you are shutting off logging for production, or because you're using * another logging system, you should Provide a simpler logging class in your module configuration. * @type {LogLevel} */ this.logLevel = 'trace'; } } const emptyFn = function (...x) { }; class Logger { constructor(configuration) { this.config = new LoggerConfiguration(); this.config = configuration || this.config; this.applyLevel(); } trace(context, ...message) { this.log(new LogMessage('trace', context, ...message)); } debug(context, ...message) { this.log(new LogMessage('debug', context, ...message)); } info(context, ...message) { this.log(new LogMessage('info', context, ...message)); } warn(context, ...message) { this.log(new LogMessage('warn', context, ...message)); } error(context, ...message) { this.log(new LogMessage('error', context, ...message)); } fatal(context, ...message) { this.log(new LogMessage('fatal', context, ...message)); } applyLevel() { console.log('Logger', 'applyLevel', this.config); /** * This keeps noise off the system bus when running in production mode or with logging off. * Yes, it's supposed to fall through, despite the evil nature. */ // @ts-ignore // noinspection FallThroughInSwitchStatementJS switch (this.config.logLevel) { // @ts-ignore case LogLevels.NONE: this.fatal = emptyFn; // @ts-ignore case LogLevels.fatal: this.error = emptyFn; // @ts-ignore case LogLevels.error: this.warn = emptyFn; // @ts-ignore case LogLevels.warn: this.info = emptyFn; // @ts-ignore case LogLevels.info: this.debug = emptyFn; // @ts-ignore case LogLevels.debug: this.trace = emptyFn; // @ts-ignore } } } Logger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger, deps: [{ token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); Logger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: Logger, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: LoggerConfiguration, decorators: [{ type: Optional }] }]; } }); const spaces = ' '; /** * Singleton. Attempting to run two Logger instances will fail. And rightly so! */ class ConsoleLogger extends Logger { constructor(configuration) { super(configuration); } log(message) { let args = [message.level + ':']; let name = ''; if (message.context && !this.config.includeFullContext && message.context.constructor) { name = message.context._proto_ ? message.context._proto_.name : message.context.constructor.name; } const padChars = this.config.contextAsStringWidth - name.length; name = padChars > 0 ? name + spaces.substring(0, padChars) : name; args.push(name + ' - '); args = args.concat(message.message); if (this.config.includeFullContext && message.context) { args.push(message.context); } console.log.apply(console, args); } } ConsoleLogger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger, deps: [{ token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); ConsoleLogger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: ConsoleLogger, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: LoggerConfiguration, decorators: [{ type: Optional }] }]; } }); class BusLoggerConfiguration extends LoggerConfiguration { constructor() { super(...arguments); this.alsoLogToConsole = false; } } BusLoggerConfiguration.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); BusLoggerConfiguration.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLoggerConfiguration, decorators: [{ type: Injectable }] }); /** * Singleton. Attempting to run two Logger instances will fail. And rightly so! */ class BusLogger extends ConsoleLogger { constructor(bus, configuration) { super(configuration); this.bus = bus; this.config = new BusLoggerConfiguration(); console.log('BusLogger', 'constructor', configuration); } log(message) { this.bus.post(message); if (this.config.alsoLogToConsole) { super.log(message); } } } BusLogger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger, deps: [{ token: MessageBus }, { token: LoggerConfiguration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); BusLogger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.10", ngImport: i0, type: BusLogger, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: MessageBus }, { type: LoggerConfiguration, decorators: [{ type: Optional }] }]; } }); class NavigationMessage extends BusMessage { constructor(key, path, additionalMessage) { super(NavigationMessage.SourceKey, 'notification', key); this.path = path; this.additionalMessage = additionalMessage; } static filter(bus) { return bus.all.pipe(filter(m => m.source === NavigationMessage.SourceKey)); } } NavigationMessage.SourceKey = 'NavigationMessage'; class NavigationRequiresAuthenticationMessage extends NavigationMessage { constructor(path) { super(NavigationRequiresAuthenticationMessage.Key, path); } static post(bus, path) { bus.post(new NavigationRequiresAuthenticationMessage(path)); } } NavigationRequiresAuthenticationMessage.Key = 'requiresAuthentication'; class NavigationRequiresRoleMessage extends NavigationMessage { constructor(path, roleKey) { super(NavigationRequiresRoleMessage.Key, path, 'Role Required: ' + roleKey); this.roleKey = roleKey; } static post(bus, path, roleKey) { bus.post(new NavigationRequiresRoleMessage(path, roleKey)); } } NavigationRequiresRoleMessage.Key = 'requiresRole'; class NavigationRequiresPermissionMessage extends NavigationMessage { constructor(path, permissionKey) { super(NavigationRequiresPermissionMessage.SubKey, path, 'Permission Required: ' + permissionKey); this.permissionKey = permissionKey; } static post(bus, path, roleKey) { bus.post(new NavigationRequiresPermissionMessage(path, roleKey)); } } NavigationRequiresPermissionMessage.SubKey = 'requiresPermission'; class AppMessage extends BusMessage { constructor(intent, key) { super(AppMessage.SourceKey, intent, key); } static filter(bus) { return bus.all.pipe(filter$1(msg => msg.source === AppMessage.SourceKey)); } static signOutRequest() { return new AppMessage('request', AppMessage.SignOutRequest); } } AppMessage.SourceKey = 'App'; AppMessage.SignOutRequest = 'signOutRequest'; const DefaultPageAnalytics = function () { return { events: { load: true, unload: true } }; }; class NgRouteUtil { static fullPath(route) { let pathAry = []; route.pathFromRoot .map(routeSegment => routeSegment.snapshot) .map(routeSnap => { return routeSnap; }) .map(routeSnap => routeSnap.url) .filter(segments => segments && segments.length > 0) .forEach(segments => segments.forEach(segment => pathAry.push(segment.toString()))); let path = pathAry.join('/'); if (path && path.endsWith('/')) { path = path.substring(0, path.length - 1); } return path; } static primaryLeaf(router) { let c = router.routerState.root; while (c.firstChild) { c = c.firstChild; } return c; } static findDescendantByComponentKey(router, componentTypeKey) { let c = router.routerState.root; do { if (c.component && c.component['Key'] == componentTypeKey) { break; } c = c.firstChild; } while (c); return c; } /** * Breadth first search of route to find the descendant where 'parent.children[x].component['Key'] === componentTypeKey' * This requires that the Component have the static field 'Key' declared and set to a value. * @param route * @param componentTypeKey * @returns {Route | null} */ static findDescendantRouteByComponentKey(route, componentTypeKey) { let result = null; if (route.children) { for (let i = 0; i < route.children.length; i++) { let child = route.children[i]; if (child.component && child.component['Key'] === componentTypeKey) { result = child; break; } } if (!result) { for (let i = 0; i < route.children.length; i++) { result = NgRouteUtil.findDescendantRouteByComponentKey(route.children[i], componentTypeKey); if (result) { break; } } } } return result; } /** * Breadth first search of route to find the descendant where 'parent.children[x].path === path' * @param route * @param path * @returns {Route | null} */ static findDescendantRouteByPath(route, path) { let result = null; if (route.children) { for (let i = 0; i < route.children.length; i++) { let child = route.children[i]; if (child.path === path) { result = child; break; } } if (!result) { for (let i = 0; i < route.children.length; i++) { result = NgRouteUtil.findDescendantRouteByPath(route.children[i], path); if (result) { break; } } } } return result; } } const TimeUnitSort = (b, a) => { return a.orderIndex - b.orderIndex; }; const TimeUnits = { day: { unitKey: 'day', fullLabel: 'Day', label: 'day', separatorSuffix: 'd ', logicalMax: 7, momentKey: 'd', orderIndex: 40, next: 'h', previous: undefined }, h: { unitKey: 'h', fullLabel: 'Hour', label: 'hour', separatorSuffix: ':', logicalMax: 23, momentKey: 'h', orderIndex: 30, next: 'min', previous: 'day' }, min: { unitKey: 'min', fullLabel: 'Minute', label: 'min', separatorSuffix: ':', logicalMax: 59, momentKey: 'm', orderIndex: 20, next: 's', previous: 'h' }, s: { unitKey: 's', fullLabel: 'Second', label: 'sec', separatorSuffix: '.', logicalMax: 59, momentKey: 's', orderIndex: 10, next: 'ms', previous: 'min' }, ms: { unitKey: 'ms', fullLabel: 'Millisecond', label: 'ms', separatorSuffix: '', logicalMax: 999, momentKey: 'ms', orderIndex: 0, next: undefined, previous: 's' }, }; const TimeUnitKeySort = (a, b) => { return TimeUnits[b].orderIndex - TimeUnits[a].orderIndex; }; class Hacks { static materialDesignPlaceholderText(changeDetector) { setTimeout(() => { changeDetector.markForCheck(); }, 100); } } class LocalizationUtil { static browserLanguages() { let languages; if (navigator['languages']) { languages = navigator['languages']; } else { languages = [navigator.language]; } return languages; } } const adjectives = [ 'Abrupt', 'Acidic', 'Adorable', 'Adventurous', 'Aggressive', 'Agitated', 'Alert', 'Aloof', 'Amiable', 'Amused', 'Annoyed', 'Antsy', 'Anxious', 'Appalling', 'Appetizing', 'Apprehensive', 'Arrogant', 'Astonishing', 'Attractive', 'Batty', 'Beefy', 'Bewildered', 'Biting', 'Bitter', 'Bland', 'Blushing', 'Bored', 'Brave', 'Bright', 'Broad', 'Bulky', 'Burly', 'Charming', 'Cheeky', 'Cheerful', 'Clean', 'Clear', 'Cloudy', 'Clueless', 'Clumsy', 'Colorful', 'Colossal', 'Combative', 'Comfortable', 'Confused', 'Contemplative', 'Convincing', 'Convoluted', 'Cooperative', 'Corny', 'Costly', 'Courageous', 'Crabby', 'Creepy', 'Crooked', 'Cumbersome', 'Cynical', 'Dangerous', 'Dashing', 'Deep', 'Defeated', 'Defiant', 'Delicious', 'Delightful', 'Depraved', 'Despicable', 'Determined', 'Dilapidated', 'Diminutive', 'Disgusted', 'Distinct', 'Distraught', 'Distressed', 'Disturbed', 'Dizzy', 'Drab', 'Drained', 'Dull', 'Eager', 'Ecstatic', 'Elated', 'Elegant', 'Embarrassed', 'Enchanting', 'Encouraging', 'Energetic', 'Enormous', 'Enthusiastic', 'Envious', 'Exasperated', 'Excited', 'Exhilarated', 'Extensive', 'Exuberant', 'Fancy', 'Fantastic', 'Fierce', 'Filthy', 'Flat', 'Floppy', 'Fluttering', 'Foolish', 'Frantic', 'Fresh', 'Friendly', 'Frothy', 'Frustrating', 'Funny', 'Fuzzy', 'Gaudy', 'Gentle', 'Giddy', 'Gigantic', 'Glamorous', 'Gleaming', 'Glorious', 'Gorgeous', 'Graceful', 'Gritty', 'Grubby', 'Grumpy', 'Handsome', 'Happy', 'Harebrained', 'Healthy', 'Helpful', 'Hollow', 'Homely', 'Huge', 'Icy', 'Ideal', 'Immense', 'Impressionable', 'Intrigued', 'Itchy', 'Jealous', 'Jittery', 'Jolly', 'Joyous', 'Juicy', 'Jumpy', 'Kind', 'Lackadaisical', 'Lazy', 'Little', 'Lively', 'Livid', 'Lonely', 'Loose', 'Lovely', 'Lucky', 'Ludicrous', 'Macho', 'Magnificent', 'Mammoth', 'Maniacal', 'Massive', 'Melancholy', 'Melted', 'Miniature', 'Minute', 'Mistaken', 'Misty', 'Moody', 'Muddy', 'Mysterious', 'Narrow', 'Naughty', 'Nervous', 'Nonchalant', 'Nonsensical', 'Nutritious', 'Nutty', 'Oblivious', 'Obnoxious', 'Odd', 'Old-fashioned', 'Outrageous', 'Perfect', 'Perplexed', 'Petite', 'Petty', 'Plain', 'Pleasant', 'Poised', 'Pompous', 'Precious', 'Prickly', 'Proud', 'Pungent', 'Puny', 'Quaint', 'Quizzical', 'Ratty', 'Reassured', 'Relieved', 'Responsive', 'Ripe', 'Robust', 'Rough', 'Round', 'Salty', 'Sarcastic', 'Scant', 'Scary', 'Scattered', 'Scrawny', 'Selfish', 'Shaggy', 'Shaky', 'Shallow', 'Sharp', 'Shiny', 'Short', 'Silky', 'Silly', 'Skinny', 'Slippery', 'Small', 'Smarmy', 'Smiling', 'Smoggy', 'Smooth', 'Smug', 'Soggy', 'Solid', 'Sore', 'Sour', 'Sparkling', 'Spicy', 'Splendid', 'Spotless', 'Square', 'Stale', 'Steady', 'Steep', 'Sticky', 'Stormy', 'Stout', 'Strange', 'Strong', 'Stunning', 'Substantial', 'Successful', 'Succulent', 'Superficial', 'Superior', 'Swanky', 'Sweet', 'Tart', 'Tasty', 'Teeny', 'Tender', 'Tense', 'Terrible', 'Testy', 'Thankful', 'Thick', 'Thoughtful', 'Thoughtless', 'Timely', 'Tricky', 'Trite', 'Pated', 'Uneven', 'Unsightly', 'Upset', 'Uptight', 'Vast', 'Vexed', 'Victorious', 'Virtuous', 'Vivacious', 'Vivid', 'Wacky', 'Whimsical', 'Whopping', 'Wicked', 'Witty', 'Wobbly', 'Wonderful', 'Worried', 'Yummy', 'Zany', 'Zealous', 'Zippy' ]; const nouns = [ 'Aardvark', 'Aardwolf', 'Albatross', 'Alligator', 'Alpaca', 'Anaconda', 'Anglerfish', 'Ant', 'Anteater', 'Antelope', 'Antlion', 'Ape', 'Aphid', 'Armadillo', 'Asp', 'Baboon', 'Badger', 'Bandicoot', 'Barnacle', 'Barracuda', 'Basilisk', 'Bass', 'Bat', 'Bear', 'Beaver', 'Bedbug', 'Bee', 'Beetle', 'Bison', 'Blackbird', 'Boa', 'Bobcat', 'Bobolink', 'Bonobo', 'Booby', 'Bovid', 'Buffalo', 'Bug', 'Butterfly', 'Buzzard', 'Camel', 'Canid', 'Capybara', 'Cardinal', 'Caribou', 'Carp', 'Caterpillar', 'Catfish', 'Catshark', 'Centipede', 'Cephalopod', 'Chameleon', 'Cheetah', 'Chickadee', 'Chimpanzee', 'Chinchilla', 'Chipmunk', 'Cicada', 'Clam', 'Clownfish', 'Cobra', 'Cockroach', 'Cod', 'Condor', 'Constrictor', 'Coral', 'Cougar', 'Cow', 'Coyote', 'Coypu', 'Crab', 'Crane', 'Crawdad', 'Crayfish', 'Cricket', 'Crocodile', 'Crow', 'Cuckoo', 'Damselfly', 'Deer', 'Dingo', 'Dolphin', 'Dormouse', 'Dove', 'Dragon', 'Dragonfly', 'Eagle', 'Earthworm', 'Earwig', 'Echidna', 'Eel', 'Egret', 'Elephant', 'Elk', 'Emu', 'Ermine', 'Falcon', 'Ferret', 'Finch', 'Firefly', 'Fish', 'Flamingo', 'Flea', 'Fly', 'Flyingfish', 'Fowl', 'Fox', 'Fox', 'Frog', 'Gazelle', 'Gecko', 'Gerbil', 'Gibbon', 'Giraffe', 'Goldfish', 'Gopher', 'Gorilla', 'Grasshopper', 'Grouse', 'Guanaco', 'Gull', 'Guppy', 'Haddock', 'Halibut', 'Hamster', 'Hare', 'Harrier', 'Hawk', 'Hedgehog', 'Heron', 'Herring', 'Hippopotamus', 'Hookworm', 'Hornet', 'Hoverfly', 'Hummingbird', 'Hyena', 'Iguana', 'Impala', 'Insect', 'Jacana', 'Jackal', 'Jaguar', 'Jay', 'Jellyfish', 'Junglefowl', 'Kangaroo', 'Kingfisher', 'Kite', 'Kiwi', 'Koala', 'Koi', 'Krill', 'Ladybug', 'Lamprey', 'Landfowl', 'Lark', 'Leech', 'Lemming', 'Lemur', 'Leopard', 'Leopard', 'Leopard', 'Leopon', 'Limpet', 'Lion', 'Lizard', 'Llama', 'Lobster', 'Locust', 'Loon', 'Louse', 'Lungfish', 'Lynx', 'Macaw', 'Mackerel', 'Magpie', 'Mammal', 'Manatee', 'Mandrill', 'Marlin', 'Marmoset', 'Marmot', 'Marsupial', 'Marten', 'Mastodon', 'Meadowlark', 'Meerkat', 'Mink', 'Minnow', 'Mite', 'Mockingbird', 'Mole', 'Mollusk', 'Mongoose', 'Monkey', 'Moose', 'Mosquito', 'Moth', 'Mouse', 'Mule', 'Muskox', 'Narwhal', 'Needlefish', 'Newt', 'Nighthawk', 'Nightingale', 'Numbat', 'Ocelot', 'Octopus', 'Okapi', 'Olingo', 'Opossum', 'Orangutan', 'Orca', 'Oribi', 'Ostrich', 'Otter', 'Owl', 'Ox', 'Panda', 'Panther', 'Panther', 'Parakeet', 'Parrot', 'Parrotfish', 'Partridge', 'Peacock', 'Peafowl', 'Pelican', 'Penguin', 'Perch', 'Pheasant', 'Pig', 'Pike', 'Pinniped', 'Piranha', 'Planarian', 'Platypus', 'Pony', 'Porcupine', 'Porpoise', 'Possum', 'Prawn', 'Primate', 'Ptarmigan', 'Puffin', 'Puma', 'Python', 'Quail', 'Quelea', 'Quokka', 'Raccoon', 'Rat', 'Rattlesnake', 'Raven', 'Reindeer', 'Reptile', 'Rhinoceros', 'Roadrunner', 'Rodent', 'Rook', 'Rooster', 'Roundworm', 'Sailfish', 'Salamander', 'Salmon', 'Sawfish', 'Scallop', 'Scorpion', 'Seahorse', 'Shrew', 'Shrimp', 'Silkworm', 'Silverfish', 'Skink', 'Skunk', 'Sloth', 'Slug', 'Smelt', 'Snail', 'Snipe', 'Sole', 'Sparrow', 'Spider', 'Spoonbill', 'Squid', 'Squirrel', 'Starfish', 'Stingray', 'Stoat', 'Stork', 'Sturgeon', 'Swallow', 'Swan', 'Swift', 'Swordfish', 'Swordtail', 'Tahr', 'Takin', 'Tapir', 'Tarantula', 'Tarsier', 'Termite', 'Tern', 'Thrush', 'Tick', 'Tiger', 'Tiglon', 'Titi', 'Toad', 'Tortoise', 'Toucan', 'Trout', 'Tuna', 'Turtle', 'Tyrannosaurus', 'Urial', 'Vaquita', 'Vicuña', 'Viper', 'Voalavoanala', 'Vole', 'Vulture', 'Wallaby', 'Walrus', 'Warbler', 'Wasp', 'Waterbuck', 'Weasel', 'Whale', 'Whippet', 'Whitefish', 'Wildcat', 'Wildebeest', 'Wildfowl', 'Wolf', 'Wolf', 'Wolverine', 'Wombat', 'Woodchuck', 'Woodpecker', 'Worm', 'Wren', 'Xerinae', 'Yak', 'Zebra', 'Zebu', 'Zorilla', ]; class NameGenerator { static generate() { const aRand = Math.floor(NameGenerator.adjectivesLength * Math.random()); const nRand = Math.floor(NameGenerator.nounsLength * Math.random()); return adjectives[aRand] + ' ' + nouns[nRand]; } } NameGenerator.adjectivesLength = adjectives.length; NameGenerator.nounsLength = nouns.length; class NgUtil { static data$(route) { return route.data.pipe(map((data) => { return NgUtil.collectFromRoute(route.snapshot, true); })); } static data(route) { return NgUtil.collectFromRoute(route, true); } static params(route) { return NgUtil.collectFromRoute(route, false); } static collectFromRoute(route, data) { const datas = [{}]; let child = route.root; while (child) { const what = data ? child.data : child.params; datas.push(what || {}); child = child.firstChild; } // merge them all together... return Object.assign.apply(Object, datas); } static params$(route) { return route.params.pipe(map((params) => { return NgUtil.collectFromRoute(route.snapshot, false); })); } static routeLeaf(route) { let child = route.root; while (child.firstChild) { child = child.firstChild; } return child; } static keylessUrl(route) { return route.url ? route.url.split('/').map(segment => NgUtil.isFirebaseId(segment) ? ':key' : segment).join('/') : ''; } /** * * @param key * @returns {boolean} * @deprecated See FireBlanket.util#isFirebaseGeneratedId */ static isFirebaseId(key) { let isKey = false; if (key && key.length === 20 && key.startsWith('-')) { isKey = true; } return isKey; } } class TransformUtil { static firstExisting(...obj) { let result; for (let i = 0; i < obj.length; i++) { if (ObjectUtil.exists(obj[i])) { result = obj[i]; break; } } return result; } } /** * Cannot implement 'OnInit' any longer; Angular inspects for that and requires a decorator. */ class Page { constructor(bus) { this.bus = bus; this.routeInfo = { page: { title: this.constructor['name'] }, showAds: false }; } } /* * Public API Surface of core */ /** * Generated bundle index. Do not edit. */ export { AppEnvironment, AppMessage, ArrayUtils, BusLogger, BusLoggerConfiguration, BusMessage, CodedError, ConsoleLogger, DefaultPageAnalytics, Guard, Hacks, Intention, JsonUtil, LocalizationUtil, LogLevels, LogMessage, Logger, LoggerConfiguration, MessageBus, NameGenerator, NavigationMessage, NavigationRequiresAuthenticationMessage, NavigationRequiresPermissionMessage, NavigationRequiresRoleMessage, NgRouteUtil, NgUtil, ObjMapUtil, ObjectUtil, Page, ReactiveUtil, ResolveVoid, SelectionEntry, SelectionList, StringUtil, TimeUnitKeySort, TimeUnitSort, TimeUnits, TransformUtil, cleanFirebaseMap, eachKey, ensureExists, generatePushID, pathExists, removeIfExists, safe }; //# sourceMappingURL=tangential-core.mjs.map