PageSourceSearch

https://mywaytogo.org/js/system.js

js mywaytogo.org collected 2026-09-28 06:07:35 UTC 186,217 bytes, 4,513 lines download raw bytes

1'use strict';
2var __assign = (this && this.__assign) || function () {
3    __assign = Object.assign || function(t) {
4        for (var s, i = 1, n = arguments.length; i < n; i++) {
5            s = arguments[i];
6            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7                t[p] = s[p];
8        }
9        return t;
10    };
11    return __assign.apply(this, arguments);
12};
13var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15    return new (P || (P = Promise))(function (resolve, reject) {
16        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19        step((generator = generator.apply(thisArg, _arguments || [])).next());
20    });
21};
22var __generator = (this && this.__generator) || function (thisArg, body) {
23    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25    function verb(n) { return function (v) { return step([n, v]); }; }
26    function step(op) {
27        if (f) throw new TypeError("Generator is already executing.");
28        while (g && (g = 0, op[0] && (_ = 0)), _) try {
29            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30            if (y = 0, t) op = [op[0] & 2, t.value];
31            switch (op[0]) {
32                case 0: case 1: t = op; break;
33                case 4: _.label++; return { value: op[1], done: false };
34                case 5: _.label++; y = op[1]; op = [0]; continue;
35                case 7: op = _.ops.pop(); _.trys.pop(); continue;
36                default:
37                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41                    if (t[2]) _.ops.pop();
42                    _.trys.pop(); continue;
43            }
44            op = body.call(thisArg, _);
45        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47    }
48};
49var __rest = (this && this.__rest) || function (s, e) {
50    var t = {};
51    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
52        t[p] = s[p];
53    if (s != null && typeof Object.getOwnPropertySymbols === "function")
54        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
55            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
56                t[p[i]] = s[p[i]];
57        }
58    return t;
59};
60var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
61    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
62        if (ar || !(i in from)) {
63            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
64            ar[i] = from[i];
65        }
66    }
67    return to.concat(ar || Array.prototype.slice.call(from));
68};
69var authComponents = angular.module('authComponents', []);
70authComponents.component('googleSignIn', {
71    template: '<div id="{{ $ctrl.buttonId }}"></div>',
72    controller: function (CONFIG, $http, $vhttp, $timeout, vSession, Dialogs) {
73        var $ctrl = this;
74        var gAuth;
75        $ctrl.buttonId = 'g-signin';
76        $ctrl.$onInit = function () {
77            gAuth = gapi.auth2.getAuthInstance();
78            $timeout(function () {
79                gapi.signin2.render($ctrl.buttonId, {
80                    scope: 'profile email',
81                    longtitle: true,
82                });
83            });
84            if (gAuth.isSignedIn.get()) {
85                $ctrl.signInChange(true);
86            }
87            gAuth.isSignedIn.listen($ctrl.signInChange);
88        };
89        $ctrl.signInChange = function (signedIn) {
90            if (signedIn) {
91                $vhttp
92                    .post('/sso/google', {
93                    token: gAuth.currentUser.get().getAuthResponse().id_token,
94                })
95                    .then(function (res) {
96                    delete $http.defaults.headers.common.Authorization;
97                    vSession.refresh();
98                })
99                    .catch(function (err) {
100                    gAuth.disconnect();
101                    Dialogs.alert('Unauthorized: User account was not found.');
102                });
103            }
104        };
105    },
106});
107;
108'use strict';
109var chartModule = angular.module('chartComponents', []);
110chartModule.component('timeSeriesChart', timeSeriesChartComponent());
111chartModule.service('ChartUtilityService', ChartUtilityService);
112chartModule.directive('kendoChartResizeObserver', kendoChartResizeObserver);
113function kendoChartResizeObserver() {
114    return {
115        require: 'kendoChart',
116        restrict: 'A',
117        link: function (scope, element, attrs) {
118            var resizeObserver = new ResizeObserver(function (entries) {
119                for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
120                    var entry = entries_1[_i];
121                    if (entry.target === element[0]) {
122                        var chart = element.data('kendoChart');
123                        if (chart) {
124                            chart.redraw();
125                        }
126                    }
127                }
128            });
129            resizeObserver.observe(element[0]);
130            scope.$on('$destroy', function () {
131                resizeObserver.disconnect();
132            });
133        },
134    };
135}
136function ChartUtilityService() {
137    var UTIL = {};
138    UTIL.CHART_THEME = 'metro';
139    UTIL.GRANULARITY_TYPES = {
140        AUTO: 'Auto',
141        MINUTES: 'Minutes',
142        HOURS: 'Hours',
143        DAYS: 'Days',
144        WEEKS: 'Weeks',
145        MONTHS: 'Months',
146    };
147    UTIL.CHART_TYPES = {
148        AREA: 'area',
149        BAR: 'bar',
150        COLUMN: 'column',
151        LINE: 'line',
152        WATERFALL: 'waterfall',
153    };
154    UTIL.TIME_RANGE_TYPES = {
155        SYNC_WITH_REPORT: 'Sync With Report',
156        LAST_7_DAYS: 'Last 7 Days',
157        LAST_WEEK: 'Last Week',
158        LAST_30_DAYS: 'Last 30 Days',
159    };
160    UTIL.DEFAULT_TIME_RANGE = UTIL.TIME_RANGE_TYPES.SYNC_WITH_REPORT;
161    UTIL.DEFAULT_TIME_RANGE_OPTIONS = _.values(UTIL.TIME_RANGE_TYPES);
162    UTIL.CHART_AGGREGATES = {
163        SUM: 'sum',
164        AVG: 'avg',
165        MIN: 'min',
166        MAX: 'max',
167        COUNT: 'count',
168    };
169    UTIL.TS_REPORT_AGGREGATES = {
170        FIRST: 'First',
171        LAST: 'Last',
172        MIN: 'Min',
173        MAX: 'Max',
174        SUM: 'Sum',
175        AVG: 'Avg',
176        COUNT: 'Count',
177    };
178    UTIL.DAY_CATEGORY_FILTER_OPTIONS = __spreadArray([
179        { name: 'All', value: null },
180        { name: 'Weekdays', value: '2,3,4,5,6' },
181        { name: 'Weekends', value: '1,7' }
182    ], _.map(moment.weekdays(), function (day, i) { return ({ name: day, value: "".concat(i + 1) }); }), true);
183    UTIL.CHART_OPTIONS = {
184        DEFAULT_GRANULARITY_OPTIONS: _.values(UTIL.GRANULARITY_TYPES),
185        DEFAULT_CHART_TYPES: _.without(_.values(UTIL.CHART_TYPES), UTIL.CHART_TYPES.WATERFALL),
186        DEFAULT_CATEGORY_OPTIONS: [
187            UTIL.GRANULARITY_TYPES.DAYS,
188            UTIL.GRANULARITY_TYPES.HOURS,
189        ],
190    };
191    UTIL.TOOLBAR_DEFAULTS = {
192        showToolbar: true,
193        showVizList: true,
194        showChartTypes: true,
195        showTimeRange: false,
196        showDayCategoryFilter: false,
197        defaultCategoryFilter: null,
198        categoryFilterOptions: UTIL.DAY_CATEGORY_FILTER_OPTIONS,
199        timeRangeOptions: UTIL.DEFAULT_TIME_RANGE_OPTIONS,
200        defaultTimeRange: UTIL.DEFAULT_TIME_RANGE,
201        chartTypes: UTIL.CHART_OPTIONS.DEFAULT_CHART_TYPES,
202        showDateRange: true,
203        showGranularity: true,
204        defaultGranularity: UTIL.GRANULARITY_TYPES.AUTO,
205        granularityOptions: UTIL.CHART_OPTIONS.DEFAULT_GRANULARITY_OPTIONS,
206        defaultCategoryField: 'dateTime',
207        showLineSmoothing: true,
208        exportToPNG: true,
209        exportToPDF: true,
210        exportToSVG: true,
211    };
212    UTIL.TIME_SERIES_CHART_DEFAULTS = {
213        theme: UTIL.CHART_THEME,
214        legend: {
215            position: 'bottom',
216        },
217        seriesDefaults: {
218            type: UTIL.CHART_TYPES.AREA,
219            style: 'smooth',
220            aggregate: '',
221            missingValues: 'interpolate',
222            markers: {
223                visible: false,
224            },
225        },
226        series: [],
227        valueAxis: {
228            labels: {
229                format: '{0}',
230            },
231            line: {
232                visible: false,
233            },
234        },
235        categoryAxis: {
236            categories: [],
237            majorGridLines: {
238                visible: false,
239            },
240            type: 'date',
241            baseUnit: 'fit',
242            roundToBaseUnit: true,
243            labels: {
244                rotation: {
245                    angle: 'auto',
246                },
247            },
248        },
249        tooltip: {
250            visible: true,
251            format: '{3} {0}%',
252            template: function (e) {
253                var template = "<b>".concat(e.series.name, ": ").concat(e.value, "</b>");
254                if (!_.isDate(e.category))
255                    return template;
256                var date = moment(e.category).format('MM/DD/YYYY hh:mm A');
257                return "".concat(template, " <br/> <b>Date: ").concat(date, "</b>");
258            },
259        },
260    };
261    UTIL.CHART_COLORS = {
262        GREEN: '#8ebc00',
263        DARK_GREEN: '#309b46',
264        BLUE: '#25a0da',
265        ORANGE: '#ff6900',
266        RED: '#e61e26',
267        YELLOW: '#d8e404',
268        TEAL: '#16aba9',
269        PURPLE: '#7e51a1',
270        BLACK: '#313131',
271        PINK: '#ed1691',
272    };
273    UTIL.SUMMARY_BAR_DEFAULTS = {
274        theme: UTIL.CHART_THEME,
275        title: {
276            visible: false,
277            text: '',
278            position: 'top',
279            font: '16px "Nunito", Arial, sans-serif',
280            color: '#000000',
281        },
282        plotArea: {
283            padding: 0,
284            margin: 0,
285        },
286        chartArea: {
287            padding: 0,
288            margin: 0,
289            background: '',
290        },
291        panes: [{ clip: false, margin: 0 }],
292        seriesDefaults: {
293            visibleInLegend: true,
294            type: UTIL.CHART_TYPES.BAR,
295            stack: {
296                type: '100%',
297            },
298            labels: {
299                visible: false,
300                position: 'auto',
301                template: '#= dataItem.label #',
302            },
303            series: [],
304            margin: 0,
305            gap: 0,
306            spacing: 0,
307            visual: function (e) {
308                var visual = e.createVisual();
309                visual.transform(kendo.geometry
310                    .transform()
311                    .scale(1, 40 / e.rect.size.height, e.rect.center()));
312                return visual;
313            },
314        },
315        legend: {
316            visible: true,
317            position: 'bottom',
318        },
319        axisDefaults: {
320            labels: {
321                visible: false,
322            },
323            visibleInLegend: true,
324        },
325        valueAxis: {
326            min: 0,
327            minorGridLines: {
328                visible: false,
329            },
330            majorGridLines: {
331                visible: false,
332            },
333            line: {
334                visible: false,
335            },
336        },
337        categoryAxis: {
338            categories: [],
339            minorGridLines: {
340                visible: false,
341            },
342            majorGridLines: {
343                visible: false,
344            },
345            line: {
346                visible: false,
347            },
348        },
349        tooltip: {
350            visible: true,
351            template: '#= dataItem.tooltip#',
352        },
353    };
354    return UTIL;
355}
356function timeSeriesChartComponent() {
357    return {
358        bindings: {
359            timeSeriesChart: '<chart',
360            report: '<',
361            tsOptions: '<',
362        },
363        template: "<div class=\"d-flex flex-column position-relative\">\n  <div class=\"px-15\">\n    <div kendo-toolbar=\"$ctrl.chartToolbar\"\n         k-rebind=\"$ctrl.kendoToolbarOpts\"\n         k-ng-delay=\"$ctrl.kendoToolbarOpts\"\n         k-options=\"$ctrl.kendoToolbarOpts\"></div>\n    </div>\n    <div kendo-chart=\"$ctrl.chart\"\n         kendo-chart-resize-observer\n         k-on-render=\"$ctrl.onChartRender(kendoEvent)\"\n         style=\"width: 100%; height: 550px; padding-top: 15px;\">\n  </div>\n  <div style=\"z-index: 999\" class=\"chart-loading\"></div>\n</div>",
364        controller: function (kendo, $http, $scope, $element, ChartUtilityService, $timeout) {
365            var $ctrl = this;
366            $ctrl.defaultOptions = {
367                chartTitle: null,
368                visualizations: [],
369                toolbarOptions: ChartUtilityService.TOOLBAR_DEFAULTS,
370                chartOptions: ChartUtilityService.TIME_SERIES_CHART_DEFAULTS,
371            };
372            $ctrl.options = {
373                chartTitle: null,
374                toolbarOptions: {},
375                chartOptions: {},
376            };
377            $ctrl.vizOptions = {
378                chartTitle: null,
379                toolbarOptions: {},
380                chartOptions: {},
381            };
382            $ctrl.state = {
383                isLoading: true,
384                selectedVizName: null,
385                selectedViz: null,
386                report: {
387                    baseUrl: null,
388                    queryString: null,
389                },
390                toolbar: {},
391                chart: {},
392                chartData: {
393                    rawData: [],
394                    series: [],
395                    categories: [],
396                },
397            };
398            $ctrl.$onChanges = function (changes) {
399                return __awaiter(this, void 0, void 0, function () {
400                    var isFirstOptionsChange;
401                    return __generator(this, function (_a) {
402                        if (changes.report && $ctrl.report) {
403                            $ctrl.initReport();
404                        }
405                        if (changes.tsOptions && $ctrl.tsOptions) {
406                            isFirstOptionsChange = _.result(changes.tsOptions, 'isFirstChange');
407                            if (isFirstOptionsChange) {
408                                $ctrl.options = $ctrl.formatOptions($ctrl.tsOptions);
409                                $ctrl.updateSelectedViz();
410                            }
411                        }
412                        return [2];
413                    });
414                });
415            };
416            $ctrl.$postLink = function () {
417                if ($ctrl.state.isLoading) {
418                    kendo.ui.progress($('.chart-loading'), true);
419                }
420            };
421            $ctrl.onChartRender = _.debounce(function (event) {
422                $ctrl.setLoading(false);
423            }, 300);
424            $ctrl.formatOptions = function (tsOptions) {
425                var toolbarOptions = tsOptions.toolbarOptions, visualizations = tsOptions.visualizations, chartOptions = __rest(tsOptions, ["toolbarOptions", "visualizations"]);
426                var defaultToolbarOptions = _.defaultsDeep({}, toolbarOptions, $ctrl.defaultOptions.toolbarOptions);
427                var defaultChartOptions = _.defaultsDeep({}, chartOptions, $ctrl.defaultOptions.chartOptions);
428                var setVisDefaults = function (_a) {
429                    var toolbarOptions = _a.toolbarOptions, name = _a.name, chartOptions = __rest(_a, ["toolbarOptions", "name"]);
430                    return {
431                        toolbarOptions: _.defaults({}, toolbarOptions, defaultToolbarOptions),
432                        chartOptions: _.defaults({}, chartOptions, defaultChartOptions),
433                        name: name,
434                    };
435                };
436                var defaultVisualizations = _.map(visualizations, setVisDefaults);
437                return Object.seal({
438                    toolbarOptions: defaultToolbarOptions,
439                    chartOptions: defaultChartOptions,
440                    visualizations: defaultVisualizations,
441                });
442            };
443            $ctrl.setLoading = function (isLoading) {
444                $ctrl.state.isLoading = isLoading;
445                kendo.ui.progress($('.chart-loading'), $ctrl.state.isLoading);
446            };
447            $ctrl.refreshComponent = function () {
448                return __awaiter(this, void 0, void 0, function () {
449                    return __generator(this, function (_a) {
450                        switch (_a.label) {
451                            case 0: return [4, $ctrl.refreshChartData()];
452                            case 1:
453                                _a.sent();
454                                $ctrl.updateToolbar();
455                                $ctrl.updateChart();
456                                return [2];
457                        }
458                    });
459                });
460            };
461            $ctrl.refresh = _.debounce($ctrl.refreshComponent, 500);
462            $ctrl.updateSelectedViz = function () {
463                if (!$ctrl.state.selectedVizName) {
464                    $ctrl.state.selectedVizName = _.get(_.first($ctrl.options.visualizations), 'name');
465                }
466                var viz = _.find($ctrl.options.visualizations, {
467                    name: $ctrl.state.selectedVizName,
468                });
469                $ctrl.state.selectedViz = viz;
470                $ctrl.vizOptions.toolbarOptions =
471                    $ctrl.state.selectedViz.toolbarOptions;
472                $ctrl.vizOptions.chartOptions = $ctrl.state.selectedViz.chartOptions;
473                Object.seal($ctrl.vizOptions);
474                $ctrl.state.toolbar.chartType =
475                    $ctrl.vizOptions.chartOptions.seriesDefaults.type;
476                $ctrl.state.toolbar.style =
477                    $ctrl.vizOptions.chartOptions.seriesDefaults.style || 'normal';
478                $ctrl.state.toolbar.granularity =
479                    $ctrl.vizOptions.toolbarOptions.defaultGranularity;
480                $ctrl.state.toolbar.timeRange =
481                    $ctrl.vizOptions.toolbarOptions.defaultTimeRange;
482                $ctrl.state.toolbar.categoryDayFilter =
483                    $ctrl.vizOptions.toolbarOptions.defaultCategoryFilter;
484                $ctrl.refresh();
485            };
486            $ctrl.initReport = function () {
487                if (_.isFunction($ctrl.state.report.watcher)) {
488                    $ctrl.state.report.watcher();
489                }
490                $ctrl.state.report.watcher = $scope.$watch('$ctrl.report.lastDataUrl', function (newvalue, oldvalue) {
491                    if (newvalue) {
492                        var baseUrl = newvalue.split('?')[0];
493                        var params = newvalue.split('?')[1];
494                        params = params.split('&');
495                        var queryString = '?' + _.filter(params, function (p) { return p.match(/^filter/); }).join('&');
496                        if (queryString == '?') {
497                            queryString = '';
498                        }
499                        if (queryString !== $ctrl.state.report.queryString) {
500                            $ctrl.state.report.queryString = queryString;
501                            $ctrl.state.report.baseUrl = baseUrl.replace('data', 'time-series');
502                            $ctrl.refresh();
503                        }
504                    }
505                });
506            };
507            $ctrl.getDateRange = function (type) {
508                var range = {
509                    startDate: null,
510                    endDate: null,
511                };
512                switch (type) {
513                    case ChartUtilityService.TIME_RANGE_TYPES.LAST_7_DAYS: {
514                        range.startDate = moment()
515                            .subtract(7, 'days')
516                            .startOf('day')
517                            .toISOString();
518                        break;
519                    }
520                    case ChartUtilityService.TIME_RANGE_TYPES.LAST_30_DAYS: {
521                        range.startDate = moment()
522                            .subtract(30, 'days')
523                            .startOf('day')
524                            .toISOString();
525                        break;
526                    }
527                    case ChartUtilityService.TIME_RANGE_TYPES.LAST_WEEK: {
528                        range.startDate = moment()
529                            .subtract(1, 'week')
530                            .startOf('week')
531                            .toISOString();
532                        range.endDate = moment(range.start).endOf('week').toISOString();
533                    }
534                }
535                return range;
536            };
537            $ctrl.getTSDataUrl = function () {
538                var granularityMapping = {
539                    Auto: 'day',
540                    Minutes: '5min',
541                    Hours: 'hour',
542                    Days: 'day',
543                    Weeks: 'week',
544                    Months: 'month',
545                };
546                var queryString = $ctrl.state.report.queryString;
547                var baseUrl = "".concat($ctrl.state.report.baseUrl);
548                var chartGranularity = _.get(granularityMapping, $ctrl.state.toolbar.granularity, 'day');
549                var selectedFields = _.filter(_.map(_.get($ctrl, 'state.selectedViz.chartOptions.series', []), 'field'), _.isString);
550                var fields = _.uniq(_.compact(_.map(selectedFields, function (fieldName) {
551                    var match = fieldName.match(/^(.+)(Avg|Sum|Count|Max|Min|First|Last)$/);
552                    return match[1];
553                })));
554                var queryParams = new URLSearchParams(queryString);
555                if (!baseUrl.match(/\?/))
556                    baseUrl += '?';
557                queryParams.set('selectedFields', selectedFields.join(','));
558                queryParams.set('fields', fields.join(','));
559                queryParams.set('granularity', chartGranularity);
560                function isFilterField(str) {
561                    var pattern = /^filter\[filters\]\[\d+\]\[field\]$/;
562                    return pattern.test(str);
563                }
564                if ($ctrl.state.selectedViz.chartOptions.categoryAxis.type !== 'date') {
565                    queryParams.set('groupCategorically', 'true');
566                    if ($ctrl.state.toolbar.categoryDayFilter) {
567                        queryParams.set('categoryDayMatch', $ctrl.state.toolbar.categoryDayFilter);
568                    }
569                }
570                if ($ctrl.state.toolbar.timeRange &&
571                    $ctrl.state.toolbar.timeRange !==
572                        ChartUtilityService.TIME_RANGE_TYPES.SYNC_WITH_REPORT) {
573                    var filterCount_1 = 0;
574                    queryParams.forEach(function (value, key) {
575                        if (!isFilterField(key))
576                            return;
577                        if (value === 'dateTime') {
578                            var path = _.replace(key, '[field]', '');
579                            queryParams.delete(path);
580                        }
581                        else {
582                            filterCount_1++;
583                        }
584                    });
585                    var _a = $ctrl.getDateRange($ctrl.state.toolbar.timeRange), startDate = _a.startDate, endDate = _a.endDate;
586                    var addFilter = function (field, operator, value) {
587                        queryParams.set("filter[filters][".concat(filterCount_1, "][field]"), 'dateTime');
588                        queryParams.set("filter[filters][".concat(filterCount_1, "][operator]"), operator);
589                        queryParams.set("filter[filters][".concat(filterCount_1, "][value]"), value);
590                        filterCount_1++;
591                    };
592                    if (startDate)
593                        addFilter('dateTime', 'gte', startDate);
594                    if (endDate)
595                        addFilter('dateTime', 'lte', endDate);
596                }
597                return baseUrl + queryParams.toString();
598            };
599            $ctrl.isRawDataCurrent = function () {
600                if (!$ctrl.state.report.dataUrl ||
601                    !$ctrl.state.chartData.rawData ||
602                    !$ctrl.state.chartData.rawData.length) {
603                    return false;
604                }
605                return $ctrl.getTSDataUrl() === $ctrl.state.report.dataUrl;
606            };
607            $ctrl.retrieveUpdatedData = function () {
608                return __awaiter(this, void 0, void 0, function () {
609                    var dataUrl, res;
610                    return __generator(this, function (_a) {
611                        switch (_a.label) {
612                            case 0:
613                                dataUrl = $ctrl.getTSDataUrl();
614                                return [4, $http.get(dataUrl)];
615                            case 1:
616                                res = _a.sent();
617                                $ctrl.state.chartData.rawData = res.data;
618                                $ctrl.state.report.dataUrl = dataUrl;
619                                return [2];
620                        }
621                    });
622                });
623            };
624            $ctrl.refreshChartData = function () {
625                return __awaiter(this, void 0, void 0, function () {
626                    var rawData, vizSeries, fnCount, dataSeries;
627                    return __generator(this, function (_a) {
628                        switch (_a.label) {
629                            case 0:
630                                $ctrl.setLoading(true);
631                                if (!!$ctrl.isRawDataCurrent()) return [3, 2];
632                                return [4, $ctrl.retrieveUpdatedData()];
633                            case 1:
634                                _a.sent();
635                                _a.label = 2;
636                            case 2:
637                                rawData = $ctrl.state.chartData.rawData;
638                                vizSeries = $ctrl.state.selectedViz.chartOptions.series;
639                                fnCount = 0;
640                                dataSeries = _.map(vizSeries, function (def) {
641                                    var seriesItem = _.clone(def);
642                                    seriesItem.categoryField = _.get($ctrl.state.selectedViz.chartOptions, 'categoryAxis.categoryField', 'dateTime');
643                                    if (_.isFunction(def.field)) {
644                                        seriesItem.field = 'fn' + fnCount;
645                                        def.fnName = 'fn' + fnCount;
646                                        fnCount++;
647                                    }
648                                    return seriesItem;
649                                });
650                                rawData.forEach(function (d) {
651                                    if (d.dateTime)
652                                        d.dateTime = new Date(d.dateTime);
653                                    _.forEach(vizSeries, function (def) {
654                                        if (def.fnName) {
655                                            d[def.fnName] = def.field(d);
656                                        }
657                                    });
658                                });
659                                $ctrl.state.chartData.series = dataSeries;
660                                return [2];
661                        }
662                    });
663                });
664            };
665            $ctrl.updateToolbar = function () {
666                var toolbarOpts = $ctrl.vizOptions.toolbarOptions;
667                var getToolbarBaseOpts = function () { return ({
668                    change: function (e) {
669                        e.sender.span[0].style.textTransform = 'uppercase';
670                    },
671                    dataBound: function (e) {
672                        e.sender.span[0].style.textTransform = 'uppercase';
673                    },
674                }); };
675                $ctrl.kendoToolbarOpts = _.defaultsDeep({
676                    hidden: !toolbarOpts.showToolbar,
677                    items: [],
678                }, toolbarOpts);
679                var kendoOpts = $ctrl.kendoToolbarOpts;
680                if (toolbarOpts.showVizList) {
681                    $ctrl.vizSelectionKendoOpts = {
682                        dataTextField: 'name',
683                        dataValueField: 'name',
684                        dataSource: $ctrl.options.visualizations,
685                    };
686                    kendoOpts.items.push({
687                        template: "<input kendo-drop-down-list\n                                  k-options=\"$ctrl.vizSelectionKendoOpts\"\n                                  ng-model=\"$ctrl.state.selectedVizName\"\n                                  ng-change=\"$ctrl.updateSelectedViz()\"\n                                  style='width: 190px;' />",
688                        overflow: 'never',
689                    });
690                }
691                if (toolbarOpts.showChartTypes) {
692                    $ctrl.typeSelectionKendoOpts = getToolbarBaseOpts();
693                    kendoOpts.items.push({ type: 'separator' }, { template: '<label>CHART TYPE:</label>' }, {
694                        template: "<input kendo-drop-down-list\n                                  k-options=\"$ctrl.typeSelectionKendoOpts\"\n                                  k-data-source=\"$ctrl.vizOptions.toolbarOptions.chartTypes\",\n                                  ng-model=\"$ctrl.state.toolbar.chartType\"\n                                  ng-change=\"$ctrl.updateToolbarState()\"\n                                  style='width: 150px;' />",
695                        overflow: 'never',
696                    });
697                }
698                if (toolbarOpts.showLineSmoothing) {
699                    kendoOpts.items.push({
700                        type: 'button',
701                        id: 'line-smooth',
702                        text: 'LINE SMOOTHING',
703                        enable: $ctrl.state.toolbar.chartType.match(/area|line/),
704                        selected: $ctrl.state.toolbar.chartType.match(/area|line/) &&
705                            $ctrl.state.toolbar.style === 'smooth',
706                        togglable: true,
707                        toggle: $ctrl.updateToolbarState,
708                    });
709                }
710                if (toolbarOpts.showGranularity) {
711                    $ctrl.granularitySelectKendoOpts = getToolbarBaseOpts();
712                    kendoOpts.items.push({ type: 'separator' }, { template: '<label>SHOW:</label>' }, {
713                        template: "<input kendo-drop-down-list\n                                  k-options=\"$ctrl.granularitySelectKendoOpts\"\n                                  k-data-source=\"$ctrl.vizOptions.toolbarOptions.granularityOptions\",\n                                  ng-model=\"$ctrl.state.toolbar.granularity\"\n                                  ng-change=\"$ctrl.updateToolbarState()\"\n                                  style='width: 150px;' />",
714                        overflow: 'never',
715                    });
716                }
717                if (toolbarOpts.showDayCategoryFilter) {
718                    $ctrl.filterSelectionKendoOpts = __assign(__assign({}, getToolbarBaseOpts()), { dataSource: $ctrl.vizOptions.toolbarOptions.categoryFilterOptions, dataTextField: 'name', dataValueField: 'value' });
719                    kendoOpts.items.push({ type: 'separator' }, { template: '<label>DAYS:</label>' }, {
720                        template: "<input kendo-drop-down-list\n                                k-options=\"$ctrl.filterSelectionKendoOpts\"\n                                ng-model=\"$ctrl.state.toolbar.categoryDayFilter\"\n                                ng-change=\"$ctrl.updateToolbarState()\"\n                                style='width: 190px;' />",
721                        overflow: 'never',
722                    });
723                }
724                if (toolbarOpts.showTimeRange) {
725                    $ctrl.timeRangeKendoOpts = getToolbarBaseOpts();
726                    kendoOpts.items.push({ type: 'separator' }, { template: '<label>TIME RANGE:</label>' }, {
727                        template: "<input kendo-drop-down-list\n                                  k-options=\"$ctrl.timeRangeKendoOpts\"\n                                  k-data-source=\"$ctrl.vizOptions.toolbarOptions.timeRangeOptions\",\n                                  ng-model=\"$ctrl.state.toolbar.timeRange\"\n                                  ng-change=\"$ctrl.updateToolbarState()\"\n                                  style='width: 150px;' />",
728                        overflow: 'never',
729                    });
730                }
731                if (toolbarOpts.exportToPDF || toolbarOpts.exportToPNG) {
732                    $ctrl.exportSelectionKendoOpts = {
733                        optionLabel: 'Export',
734                        dataValueField: 'value',
735                        dataTextField: 'name',
736                        autoWidth: true,
737                        select: function (e) {
738                            e.preventDefault();
739                            switch (e.dataItem.value) {
740                                case 'pdf':
741                                    $ctrl.chart
742                                        .exportPDF({ landscape: true })
743                                        .done(function (data) {
744                                        kendo.saveAs({
745                                            dataURI: data,
746                                            fileName: 'chart.pdf',
747                                            proxyURL: '/api/v1/reporting/download-pdf',
748                                        });
749                                    });
750                                    break;
751                                case 'png':
752                                    $ctrl.chart.exportImage().done(function (data) {
753                                        kendo.saveAs({
754                                            dataURI: data,
755                                            fileName: 'chart.png',
756                                        });
757                                    });
758                                    break;
759                                case 'svg':
760                                    $ctrl.chart.exportSVG().done(function (data) {
761                                        kendo.saveAs({
762                                            dataURI: data,
763                                            fileName: 'chart.svg',
764                                        });
765                                    });
766                                    break;
767                            }
768                        },
769                        dataBound: function (e) {
770                            e.sender.span[0].style.textTransform = 'uppercase';
771                        },
772                        dataSource: [],
773                    };
774                    if (toolbarOpts.exportToPDF)
775                        $ctrl.exportSelectionKendoOpts.dataSource.pu
775sh({
776                            name: 'Export to PDF',
777                            value: 'pdf',
778                        });
779                    if (toolbarOpts.exportToPNG)
780                        $ctrl.exportSelectionKendoOpts.dataSource.push({
781                            name: 'Export to PNG',
782                            value: 'png',
783                        });
784                    if (toolbarOpts.exportToSVG)
785                        $ctrl.exportSelectionKendoOpts.dataSource.push({
786                            name: 'Export to SVG',
787                            value: 'svg',
788                        });
789                    kendoOpts.items.push({ type: 'separator' }, {
790                        template: "<input kendo-drop-down-list\n                                  k-options=\"$ctrl.exportSelectionKendoOpts\"\n                                   />",
791                        overflow: 'never',
792                    });
793                }
794            };
795            $ctrl.updateToolbarState = function (e) {
796                if (e && e.id) {
797                    switch (e.id) {
798                        case 'line-smooth':
799                            $ctrl.state.toolbar.style = e.checked ? 'smooth' : 'normal';
800                    }
801                }
802                $ctrl.updateToolbar();
803                $ctrl.updateChart();
804            };
805            $ctrl.setLine = function (e) {
806                var lineStyle = e.checked ? 'smooth' : null;
807                $ctrl.chart.setOptions({ seriesDefaults: { style: lineStyle } });
808            };
809            $ctrl.setChartType = function () {
810                var stackBtnEnabled = true;
811                var options = { seriesDefaults: { type: $ctrl.chartType } };
812                if ($ctrl.chartType === 'line') {
813                    $ctrl.chartToolbar.enable('#line-smooth', true);
814                }
815                else {
816                    $ctrl.chartToolbar.enable('#line-smooth', false);
817                }
818                if ($ctrl.chartType === 'waterfall') {
819                    stackBtnEnabled = false;
820                    $ctrl.chartToolbar.toggle('#count', true);
821                }
822                if (!stackBtnEnabled && $ctrl.stackType === '100%') {
823                    _.set(options.seriesDefaults, 'stack.type', 'normal');
824                }
825                $ctrl.chartToolbar.enable('#stackTypeGroup', stackBtnEnabled);
826                $ctrl.chart.setOptions(options);
827            };
828            $ctrl.chartOpts = {};
829            $ctrl.updateChart = function () {
830                return __awaiter(this, void 0, void 0, function () {
831                    var chartOpts, kendoOpts, chartType, chartTypes, granularity, dataPoints, chartWidth, maxLabels, step, skip;
832                    return __generator(this, function (_a) {
833                        switch (_a.label) {
834                            case 0:
835                                chartOpts = $ctrl.vizOptions.chartOptions;
836                                $ctrl.kendoChartOpts = _.cloneDeep(chartOpts);
837                                kendoOpts = $ctrl.kendoChartOpts;
838                                return [4, $ctrl.refreshChartData()];
839                            case 1:
840                                _a.sent();
841                                kendoOpts.series = $ctrl.state.chartData.series;
842                                kendoOpts.dataSource = { data: $ctrl.state.chartData.rawData };
843                                chartType = _.get($ctrl.state, 'selectedViz.toolbar.chartType', $ctrl.state.toolbar.chartType);
844                                if (chartType) {
845                                    chartTypes = _.get($ctrl.state.selectedViz, 'toolbarOptions.chartTypes', []);
846                                    if (chartTypes.length && !_.includes(chartTypes, chartType)) {
847                                        chartType = chartTypes[0];
848                                    }
849                                    kendoOpts.seriesDefaults.type = chartType;
850                                }
851                                if ($ctrl.state.toolbar.style) {
852                                    kendoOpts.seriesDefaults.style = $ctrl.state.toolbar.style;
853                                }
854                                if ($ctrl.state.toolbar.granularity &&
855                                    chartOpts.categoryAxis.type === 'date') {
856                                    granularity = $ctrl.state.toolbar.granularity;
857                                    dataPoints = _.get($ctrl.state.chartData, 'rawData', []).length;
858                                    chartWidth = kendoOpts.type === 'bar'
859                                        ? $($element).innerHeight()
860                                        : $($element).innerWidth();
861                                    maxLabels = Math.floor(chartWidth / 20);
862                                    step = Math.ceil(dataPoints / maxLabels);
863                                    skip = 0;
864                                    if (step > 1) {
865                                        skip = Math.ceil((dataPoints - maxLabels) / (maxLabels - 1));
866                                    }
867                                    kendoOpts.categoryAxis.baseUnit = 'fit';
868                                    switch (granularity) {
869                                        case 'Auto':
870                                            kendoOpts.categoryAxis.baseUnit = 'fit';
871                                            break;
872                                        case 'Minutes':
873                                            kendoOpts.categoryAxis.baseUnit = 'minute';
874                                            kendoOpts.categoryAxis.baseUnitStep = 5;
875                                            kendoOpts.categoryAxis.labels.step = step;
876                                            kendoOpts.categoryAxis.labels.skip = skip;
877                                            break;
878                                        case 'Hours':
879                                            kendoOpts.categoryAxis.baseUnit = 'hour';
880                                            kendoOpts.categoryAxis.baseUnitStep = 3;
881                                            kendoOpts.categoryAxis.labels.step = step;
882                                            kendoOpts.categoryAxis.labels.skip = skip;
883                                            break;
884                                        case 'Days':
885                                            kendoOpts.categoryAxis.baseUnit = 'day';
886                                            kendoOpts.categoryAxis.baseUnitStep = 1;
887                                            kendoOpts.categoryAxis.labels.step = step;
888                                            kendoOpts.categoryAxis.labels.skip = skip;
889                                            break;
890                                        case 'Weeks':
891                                            kendoOpts.categoryAxis.baseUnit = 'week';
892                                            kendoOpts.categoryAxis.baseUnitStep = 1;
893                                            kendoOpts.categoryAxis.labels.step = step;
894                                            kendoOpts.categoryAxis.labels.skip = skip;
895                                            break;
896                                        case 'Months':
897                                            kendoOpts.categoryAxis.baseUnit = 'month';
898                                            kendoOpts.categoryAxis.baseUnitStep = 1;
899                                            kendoOpts.categoryAxis.labels.step = step;
900                                            kendoOpts.categoryAxis.labels.skip = skip;
901                                            break;
902                                    }
903                                }
904                                $ctrl.chartOpts = kendoOpts;
905                                if ($ctrl.chart) {
906                                    $ctrl.chart.setOptions($ctrl.chartOpts);
907                                }
908                                return [2];
909                        }
910                    });
911                });
912            };
913        },
914    };
915}
916;
917'use strict';
918var appComponents = angular.module('appComponents', [
919    'inputComponents',
920    'selectionComponents',
921    'stats',
922    'authComponents',
923    'navigationComponents',
924    'formComponents',
925    'layoutComponents',
926    'widgetComponents',
927    'chartComponents',
928]);
929;
930'use strict';
931var formComponents = angular.module('formComponents', []);
932formComponents.component('adminForm', {
933    templateUrl: '/templates/system/components/forms/admin-form.html',
934    transclude: {
935        formSections: 'adminFormSections',
936        formActions: '?adminFormActions',
937        formNotes: '?adminFormNotes',
938    },
939    bindings: {
940        form: '=?',
941        onSave: '<?',
942        onUndo: '<?',
943        onDelete: '<?',
944        showActions: '<?',
945        formColWidth: '<?',
946    },
947    controller: function ($scope, $element, $transclude) {
948        var $ctrl = this;
949        $ctrl.sections = [];
950        $ctrl.showMoreActions = $transclude.isSlotFilled('formActions');
951        $ctrl.showFormNotes = $transclude.isSlotFilled('formNotes');
952        $ctrl.$onInit = function () {
953            if (!$ctrl.formColWidth) {
954                $ctrl.formColWidth = 8;
955            }
956        };
957        $ctrl.$postLink = function () {
958            $ctrl.buildTocSections();
959            $ctrl.form = $scope.adminForm;
960        };
961        $ctrl.$doCheck = function () {
962            if ($scope.adminForm) {
963                var sectionCount_1 = 0;
964                _.keys($scope.adminForm).forEach(function (key) {
965                    if (key.charAt(0) !== '$')
966                        sectionCount_1++;
967                });
968                if (sectionCount_1 !== $ctrl.sections.length) {
969                    $ctrl.buildTocSections();
970                }
971            }
972        };
973        $ctrl.buildTocSections = function () {
974            var sections = [];
975            angular.forEach($element.find('admin-form-section'), function (section) {
976                var elm = angular.element(section);
977                sections.push({ id: elm.attr('section-id'), label: elm.attr('label') });
978            });
979            $ctrl.sections = sections;
980        };
981    },
982});
983formComponents.component('adminFormSection', {
984    templateUrl: '/templates/system/components/forms/admin-form-section.html',
985    transclude: true,
986    bindings: {
987        label: '@',
988        sectionId: '@',
989    },
990});
991formComponents.component('adminFormToc', {
992    templateUrl: '/templates/system/components/forms/admin-form-toc.html',
993    bindings: {
994        sections: '<',
995        adminForm: '<',
996    },
997    controller: function (elementHelper) {
998        var $ctrl = this;
999        $ctrl.scrollTo = function (elmId) {
1000            var elm = document.getElementById(elmId);
1001            elementHelper.scrollToElement(elm);
1002        };
1003        $ctrl.getSectionStatus = function (id) {
1004            if ($ctrl.adminForm) {
1005                var formSection = $ctrl.adminForm[id];
1006                if (!formSection)
1007                    return;
1008                if (formSection.$invalid)
1009                    return 'fa-exclamation-triangle btn-warning';
1010                else if (formSection.$dirty)
1011                    return 'fa-check btn-success';
1012                else
1013                    return 'fa-edit btn-primary';
1014            }
1015        };
1016    },
1017});
1018;
1019'use strict';
1020var inputComponents = angular.module('inputComponents', []);
1021inputComponents.directive('integerCast', [
1022    function () {
1023        return {
1024            restrict: 'A',
1025            require: 'ngModel',
1026            link: function (scope, element, attrs, ngModel) {
1027                ngModel.$parsers.push(function (value) { return (!!value && 1) || 0; });
1028                ngModel.$formatters.push(function (value) { return !!value; });
1029            },
1030        };
1031    },
1032]);
1033inputComponents.component('toggleButton', {
1034    template: '<button type="button" class="btn {{ $ctrl.btnClass }}" ng-click="$ctrl.toggleState()">' +
1035        '<i class="toggle-btn-icon {{ $ctrl.checked ? $ctrl.activeIcon : $ctrl.inactiveIcon }}"></i>' +
1036        '<ng-transclude></ng-transclude>' +
1037        '</button>',
1038    transclude: true,
1039    require: {
1040        ngModel: 'ngModel',
1041    },
1042    bindings: {
1043        btnClass: '<?',
1044        activeIcon: '<?',
1045        inactiveIcon: '<?',
1046        checked: '=?',
1047        onChange: '&?',
1048    },
1049    controller: function () {
1050        var $ctrl = this;
1051        $ctrl.$onInit = function () {
1052            $ctrl.btnClass = $ctrl.btnClass || 'btn-primary btn-sm';
1053            $ctrl.activeIcon = $ctrl.activeIcon || 'far fa-check-circle';
1054            $ctrl.inactiveIcon = $ctrl.inactiveIcon || 'far fa-circle';
1055            $ctrl.checked = $ctrl.checked || false;
1056            $ctrl.ngModel.$render = function () {
1057                $ctrl.checked = $ctrl.ngModel.$viewValue;
1058            };
1059        };
1060        $ctrl.toggleState = function () {
1061            $ctrl.checked = !$ctrl.checked;
1062            $ctrl.ngModel.$setViewValue($ctrl.checked);
1063            if ($ctrl.onChange)
1064                $ctrl.onChange({ checked: $ctrl.checked });
1065        };
1066    },
1067});
1068inputComponents.component('toggleSwitch', {
1069    bindings: {
1070        checked: '=?',
1071        labelTitle: '@?',
1072        onToggle: '&?',
1073        disabled: '<?',
1074    },
1075    template: '<div ng-form="toggleSwitch" class="flex-box">' +
1076        '<label class="switch" ng-class="{disabled: $ctrl.disabled}">' +
1077        '<input ng-click="$ctrl.toggleState()" ng-checked="$ctrl.checked" type="checkbox" ng-disabled="$ctrl.disabled">' +
1078        '<span class="slider round"></span>' +
1079        '</label>' +
1080        '<label class="toggle-switch-label" >{{$ctrl.labelTitle}}</label>' +
1081        '</div>',
1082    controller: function ($scope, $timeout) {
1083        var $ctrl = this;
1084        this.toggleState = function () {
1085            this.checked = !this.checked;
1086            $scope.toggleSwitch.$setDirty();
1087            $timeout(function () { return _.result($ctrl, 'onToggle'); });
1088        };
1089    },
1090});
1091inputComponents.component('kendoUserAutocomplete', {
1092    template: '<select class="user-select" kendo-multi-select k-options="$ctrl.selectOptions" k-ng-model="$ctrl.value"></select>',
1093    require: {
1094        ngModel: 'ngModel',
1095    },
1096    bindings: {
1097        placeholder: '@',
1098        fetchUrl: '@?',
1099        onChange: '&',
1100        queryProperty: '@?',
1101        maxSelectedItems: '@?',
1102        serverPaging: '@?',
1103    },
1104    controller: function (KendoInputService, vhttp, $element) {
1105        var $ctrl = this;
1106        $ctrl.$onInit = function () {
1107            $ctrl.fetchUrl = $ctrl.fetchUrl || '/api/v1/user-autocomplete';
1108            $ctrl.textField = 'email';
1109            $ctrl.valueField = '_id';
1110            $ctrl.queryProperty = $ctrl.queryProperty || 'userQuery';
1111            $ctrl.itemTemplate =
1112                '<span class="k-state-default" style="font-size:90%">#: data.firstName # #: data.lastName # <small>(#: data.email #)</small></span>';
1113            $ctrl.autoBind = true;
1114            if (!$ctrl.placeholder) {
1115                $ctrl.placeholder = 'Select Users';
1116            }
1117            $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl);
1118            var valueMapper = {
1119                virtual: {
1120                    mapValueTo: 'dataItem',
1121                    valueMapper: function (options) {
1122                        var userLookup = _.isArray(options.value)
1123                            ? options.value.join()
1124                            : options.value;
1125                        vhttp
1126                            .get('/api/v1/user-autocomplete', { userLookup: userLookup })
1127                            .then(options.success);
1128                    },
1129                },
1130            };
1131            $ctrl.selectOptions = _.assign(KendoInputService.getSelectOptions($ctrl), valueMapper);
1132            $ctrl.ngModel.$render = function () {
1133                $ctrl.value = $ctrl.ngModel.$viewValue;
1134            };
1135        };
1136        $ctrl.$postLink = function () {
1137            var kendoEl = $element.find('select.user-select');
1138            $ctrl.multiselect = kendoEl.data('kendoMultiSelect');
1139        };
1140    },
1141});
1142inputComponents.component('kendoMultiSelectLocal', {
1143    template: '<select class="local-select" ng-readonly="$ctrl.readonly" kendo-multi-select k-options="$ctrl.selectOptions" k-ng-model="$ctrl.value"></select>',
1144    require: {
1145        ngModel: 'ngModel',
1146    },
1147    bindings: {
1148        placeholder: '@?',
1149        readonly: '=?',
1150        data: '<',
1151        textField: '@',
1152        valueField: '@',
1153        onChange: '&?',
1154        maxSelectedItems: '@?',
1155    },
1156    controller: function (KendoInputService, $element) {
1157        var $ctrl = this;
1158        $ctrl.$onInit = function () {
1159            $ctrl.dataSource = $ctrl.data;
1160            $ctrl.itemTemplate = "<span class=\"k-state-default\" style=\"font-size:90%\"><b>#: data.".concat($ctrl.textField, " #</b>");
1161            $ctrl.selectOptions = KendoInputService.getSelectOptions($ctrl);
1162            $ctrl.ngModel.$render = function () {
1163                return ($ctrl.value = $ctrl.ngModel.$viewValue || []);
1164            };
1165        };
1166        $ctrl.$onChanges = function (_a) {
1167            var data = _a.data;
1168            if (data.currentValue && $ctrl.multiselect) {
1169                var dataSource = new kendo.data.DataSource({
1170                    data: data.currentValue,
1171                });
1172                $ctrl.multiselect.setDataSource(dataSource);
1173                $ctrl.multiselect.value($ctrl.value);
1174            }
1175        };
1176        $ctrl.$postLink = function () {
1177            var kendoEl = $element.find('select.local-select');
1178            $ctrl.multiselect = kendoEl.data('kendoMultiSelect');
1179        };
1180    },
1181});
1182inputComponents.component('kendoMultiNetworkSelect', {
1183    template: '<select class="network-select" ng-readonly="$ctrl.readonly" kendo-multi-select k-options="$ctrl.selectOptions" ng-model="$ctrl.value"></select>',
1184    require: {
1185        ngModel: 'ngModel',
1186    },
1187    bindings: {
1188        placeholder: '@?',
1189        multiselect: '=?',
1190        readonly: '=?',
1191        onChange: '&',
1192        maxSelectedItems: '@?',
1193        fetchUrl: '@?',
1194        optionsFilter: '=?',
1195    },
1196    controller: function (KendoInputService, $element, $timeout) {
1197        var $ctrl = this;
1198        $ctrl.headerTemplate = "\n      <div class=\"pt-5 pb-5\" style=\"border-bottom: 1px solid darkgray;\">\n        <span class=\"fs-18 text-bold p6\">Search Results</span>\n        <span class=\"pull-right btn-link pr-5\" ng-click=\"$ctrl.clearSelection()\">Clear All</span>\n      </div>";
1199        $ctrl.$onInit = function () {
1200            $ctrl.ngModel.$render = function () {
1201                if (_.get($ctrl.ngModel, '$viewValue', []).length)
1202                    $ctrl.setUrlOverride($ctrl.ngModel.$viewValue);
1203                $ctrl.value = $ctrl.ngModel.$viewValue;
1204            };
1205            $timeout(function () {
1206                $ctrl.multiSelect = true;
1207                $ctrl.fetchUrl = $ctrl.fetchUrl || '/api/v1/network-autocomplete';
1208                $ctrl.itemTemplate = KendoInputService.getNetworkItemTemplate();
1209                $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl);
1210                $ctrl.selectOptions = KendoInputService.getNetworkRemoteOptions($ctrl);
1211                $ctrl.clearSelection = function () {
1212                    $ctrl.value = [];
1213                    $ctrl.ngModel.$setViewValue([]);
1214                };
1215            }, 300);
1216        };
1217        $ctrl.setUrlOverride = function (networkLookup) {
1218            $ctrl.getUrl = function () {
1219                var url = $ctrl.fetchUrl.split('?')[0];
1220                url += "?networkLookup=".concat(encodeURI(networkLookup));
1221                $ctrl.getUrl = null;
1222                return url;
1223            };
1224        };
1225        $ctrl.$postLink = function () {
1226            var kendoEl = $element.find('select.network-select');
1227            $ctrl.multiselect = kendoEl.data('kendoMultiSelect');
1228        };
1229    },
1230});
1231inputComponents.component('kendoNetworkDropDown', {
1232    template: '<select class="network-dropdown h-50" ng-readonly="$ctrl.readonly" kendo-drop-down-list k-options="$ctrl.selectOptions" ng-model="$ctrl.value" aria-label="network selection dropdown"></select>',
1233    require: {
1234        ngModel: 'ngModel',
1235    },
1236    bindings: {
1237        optionText: '@?',
1238        readonly: '=?',
1239        onChange: '&',
1240        fetchUrl: '@?',
1241        optionsFilter: '=?',
1242    },
1243    controller: function ($scope, KendoInputService, $element, $timeout) {
1244        var $ctrl = this;
1245        $ctrl.$onInit = function () {
1246            var name = $ctrl.optionText || 'Default (Recipients Primary Network)';
1247            $ctrl.ngModel.$render = function () {
1248                if ($ctrl.ngModel.$viewValue)
1249                    $ctrl.setUrlOverride($ctrl.ngModel.$viewValue);
1250                $ctrl.value = $ctrl.ngModel.$viewValue;
1251            };
1252            $timeout(function () {
1253                $ctrl.optionLabel = { name: name, _id: '' };
1254                $ctrl.itemTemplate = KendoInputService.getNetworkItemTemplate();
1255                $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl);
1256                $ctrl.selectOptions = KendoInputService.getNetworkRemoteOptions($ctrl);
1257            }, 100);
1258        };
1259        $ctrl.setUrlOverride = function (networkLookup) {
1260            $ctrl.getUrl = function () {
1261                var url = $ctrl.fetchUrl.split('?')[0];
1262                url += "?networkLookup=".concat(networkLookup);
1263                $ctrl.getUrl = null;
1264                return url;
1265            };
1266        };
1267        $ctrl.$postLink = function () {
1268            var kendoEl = $element.find('select.network-dropdown');
1269            $ctrl.multiselect = kendoEl.data('kendoDropDownList');
1270        };
1271        $scope.$on('scope-value-change', function () {
1272            $ctrl.dataSource = KendoInputService.getRemoteDataSource($ctrl);
1273        });
1274    },
1275});
1276inputComponents.service('KendoInputService', function ($vhttp, vSession) {
1277    var _this = this;
1278    this.getRemoteDataSource = function ($controller) {
1279        var dataSource = new kendo.data.DataSource({
1280            transport: {
1281                read: {
1282                    url: $controller.fetchUrl,
1283                    beforeSend: function (req) {
1284                        req.setRequestHeader('Authorization', 'Bearer ' + vSession.token);
1285                        if ($controller.getUrl) {
1286                            this.url = $controller.getUrl();
1287                            return;
1288                        }
1289                        var value = _.get(dataSource, '_filter.filters[0].value');
1290                        this.url = this.url.split('&filter')[0];
1291                        if (value) {
1292                            var key = $controller.queryProperty || 'name';
1293                            this.url += "&".concat(key, "=").concat(encodeURI(value));
1294                        }
1295                    },
1296                    dataFilter: function (options) {
1297                        if ($controller.optionsFilter) {
1298                            options = JSON.stringify($controller.optionsFilter(JSON.parse(options)));
1299                        }
1300                        return options;
1301                    },
1302                },
1303            },
1304            pageSize: 20,
1305            serverPaging: $controller.serverPaging === 'false' ? false : true,
1306            serverFiltering: true,
1307            serverSorting: true,
1308        });
1309        return dataSource;
1310    };
1311    this.getSelectOptions = function ($controller) {
1312        return {
1313            placeholder: $controller.placeholder || 'Select',
1314            optionLabel: $controller.optionLabel,
1315            filter: 'contains',
1316            rounded: 'sm',
1317            maxSelectedItems: $controller.maxSelectedItems || null,
1318            dataTextField: $controller.textField || 'name',
1319            dataValueField: $controller.valueField || '_id',
1320            headerTemplate: $controller.headerTemplate,
1321            value: $controller.value || [],
1322            valuePrimitive: true,
1323            autoBind: $controller.autoBind,
1324            delay: 1000,
1325            dataSource: $controller.dataSource,
1326            itemTemplate: $controller.itemTemplate,
1327            change: function (e) {
1328                var value = this.value();
1329                if (_.isString(value) && !_.size(value))
1330                    value = null;
1331                var dataItem = value && typeof this.dataItem === 'function' ? this.dataItem() : null;
1332                var name = dataItem && dataItem._id && dataItem.name ? dataItem.name : undefined;
1333                if ($controller.onChange) {
1334                    $controller.onChange({ value: value, name: name });
1335                }
1336                if ($controller.ngModel) {
1337                    $controller.ngModel.$setViewValue(value);
1338                }
1339            },
1340        };
1341    };
1342    this.getNetworkRemoteOptions = function ($controller) {
1343        var remoteOptions = {};
1344        if ($controller.multiSelect) {
1345            remoteOptions.deselect = function (e) {
1346                e.preventDefault();
1347                $controller.value = _.without($controller.value, e.dataItem._id);
1348                $controller.ngModel.$setViewValue($controller.value);
1349            };
1350        }
1351        return _.assign(remoteOptions, _this.getSelectOptions($controller));
1352    };
1353    this.getNetworkItemTemplate = function () {
1354        console.log('getNetworkItemTemplate', CONFIG.hideDetailsFromNetworkItemTemplate);
1355        if (CONFIG.hideDetailsFromNetworkItemTemplate) {
1356            return "<span class=\"k-state-default\" style=\"font-size:90%\">\n        <b>#: data.name #</b>\n      </span>";
1357        }
1358        else {
1359            return "<span class=\"k-state-default\" style=\"font-size:90%\">\n          <b>#: data.name #</b># if(data.ancestors && data.ancestors[0]) {# <br>\n          <span class=\"small\">(Parent Network - #:data.ancestors[0].name#)</span> #} #<p>#: data.description #</p>\n        </span>";
1360        }
1361    };
1362});
1363inputComponents.component('kDatePicker', {
1364    template: "\n<input\n    kendo-date-picker\n    style=\"width: 100%;\"\n    k-ng-model=\"$ctrl.date\"\n    ng-disabled=\"$ctrl.ngDisabled\"\n    k-options=\"$ctrl.kOptions\"\n    k-delay=\"$ctrl.kOptions\"\n    k-rebind=\"$ctrl.kOptions\">",
1365    require: {
1366        ngModel: 'ngModel',
1367    },
1368    bindings: {
1369        min: '<',
1370        max: '<',
1371        ngRequired: '<?',
1372        required: '<?',
1373        ngDisabled: '<?',
1374    },
1375    controller: function ($element) {
1376        var $ctrl = this;
1377        this.$postLink = function () {
1378            var _this = this;
1379            $ctrl.ngModel.$render = function () { return ($ctrl.date = $ctrl.ngModel.$viewValue); };
1380            this.ngModel.$validators.validDate = function (modelValue, viewValue) {
1381                if (!modelValue && ($ctrl.required || $ctrl.ngRequired)) {
1382                    return false;
1383                }
1384                var valid = $ctrl.validateDate(modelValue);
1385                return Boolean(valid);
1386            };
1387            this.ready = true;
1388            if (this.changesReady)
1389                _.defer(function () { return _this.initializeDatePicker(_this.ngDisabled); });
1390        };
1391        this.$onChanges = function (_a) {
1392            var min = _a.min, max = _a.max;
1393            if (this.ready) {
1394                var clear = false;
1395                if ((min && !min.currentValue && min.previousValue) ||
1396                    (max && !max.currentValue && max.previousValue))
1397                    clear = true;
1398                this.initializeDatePicker(clear);
1399            }
1400            else {
1401                this.changesReady = true;
1402            }
1403        };
1404        this.initializeDatePicker = function (clear) {
1405            var format = function (val) { return (val ? moment(val).toDate() : undefined); };
1406            var min = format(this.min);
1407            var max = format(this.max);
1408            var isValid = this.validateDate($ctrl.ngModel.$modelValue);
1409            if ($ctrl.ngDisabled) {
1410                this.ngModel.$setValidity('validDate', isValid);
1411                if (!isValid) {
1412                    $($element).find(':input').blur();
1413                }
1414                return;
1415            }
1416            else if (!clear && isValid) {
1417                this.date = $ctrl.ngModel.$modelValue;
1418            }
1419            else {
1420                this.date = undefined;
1421                this.ngModel.$setViewValue(undefined);
1422                $($element).find(':input').blur();
1423            }
1424            this.kOptions = {
1425                format: 'yyyy-MM-dd',
1426                showWeeks: false,
1427                min: min,
1428                max: max,
1429                change: function (e) {
1430                    var newVal = moment(e.sender.value());
1431                    var val = newVal.isValid() ? newVal.format() : undefined;
1432                    $ctrl.ngModel.$setViewValue(val, 'change');
1433                },
1434            };
1435        };
1436        this.validateDate = function (dateVal) {
1437            if (dateVal &&
1438                $ctrl.min &&
1439                moment(dateVal).isBefore(moment($ctrl.min, 'YYYY-MM-DD'))) {
1440                return false;
1441            }
1442            return !(dateVal &&
1443                $ctrl.max &&
1444                moment(dateVal).isAfter(moment($ctrl.max, 'YYYY-MM-DD')));
1445        };
1446    },
1447});
1448inputComponents.component('sourceOptions', {
1449    bindings: {
1450        ngModel: '=',
1451        selectId: '@',
1452        selectClass: '@?',
1453    },
1454    template: "\n    <select multiple\n            notranslate\n            ng-model=\"$ctrl.ngModel\"\n            ng-init=\"hubConfig = $ctrl.CONFIG.commuteHub.features.tripLogs\"\n            id=\"{{$ctrl.selectId}}\"\n            name=\"eligibleTripSources\"\n            class=\"form-control {{$ctrl.selectClass}}\">\n        <optgroup label=\"{{ $ctrl.ngModel && $ctrl.ngModel.length ? 'Restricted to ' + $ctrl.ngModel.length + ' Apps' : 'No Restrictions Enabled' }}\">\n            <option value=\"web\">Web Platform</option>\n            <option value=\"astro\" ng-show=\"$ctrl.CONFIG.integrations.astro\">Commute Tracker</option>\n            <option value=\"strava\" ng-show=\"$ctrl.CONFIG.integrations.strava.enabled\">Strava</option>\n            <option value=\"scoop\" ng-show=\"$ctrl.CONFIG.integrations.scoop\">Scoop</option>\n            <option value=\"ltr\" ng-show=\"$ctrl.CONFIG.integrations.ltr.enabled\">Love to Ride</option>\n            <option value=\"gps-recording\" ng-show=\"$ctrl.CONFIG.commuteHub.features.tripRecording.enabled\">GPS Recording</option>\n            <option ng-show=\"hubConfig.webAppSource\" value=\"{{hubConfig.webAppSource}}\" class=\"text-capitalize\">\n              {{hubConfig.webAppSource}}\n            </option>\n            <option ng-show=\"hubConfig.nativeAppSource\" value=\"{{hubConfig.nativeAppSource}}\" class=\"text-capitalize\">\n              {{hubConfig.nativeAppSource}}\n            </option>\n        </optgroup>\n    </select>\n  ",
1455    controller: function (CONFIG) {
1456        var $ctrl = this;
1457        $ctrl.CONFIG = CONFIG;
1458    },
1459});
1460;
1461'use strict';
1462var layoutComponents = angular.module('layoutComponents', []);
1463layoutComponents.component('dashboardWidget', {
1464    transclude: {
1465        widgetHeader: '?widgetHeader',
1466        widgetContent: 'widgetContent',
1467        widgetFooter: '?widgetFooter',
1468    },
1469    templateUrl: '/templates/system/components/layout/dashboard-widget.html',
1470    controller: function () { },
1471});
1472layoutComponents.component('programCard', {
1473    transclude: {
1474        cardImage: '?cardImage',
1475        cardHeader: 'cardHeader',
1476        cardContent: 'cardContent',
1477        cardFooter: '?cardFooter',
1478    },
1479    templateUrl: '/templates/system/components/layout/program-card.html',
1480});
1481;
1482'use strict';
1483var navigationComponents = angular.module('navigationComponents', []);
1484navigationComponents.component('breadcrumbs', {
1485    transclude: true,
1486    template: '<h3 ng-transclude></h3>',
1487    controller: function () {
1488        var $ctrl = this;
1489    },
1490});
1491navigationComponents.component('tabs', {
1492    bindings: {
1493        tabs: '=',
1494        selectedTab: '=',
1495        setTabValue: '<?',
1496        onTabChange: '&?',
1497        disableStateUpdate: '=?',
1498    },
1499    template: "\n    <div class=\"d-flex flex-row py-15\">\n      <div ng-repeat=\"tab in ::$ctrl.tabOptions\" class=\"mr-15\">\n        <button class=\"tab-button btn btn-normal ls-2 text-uppercase bg-white\" ng-click=\"$ctrl.setTab(tab.value)\" ng-class=\"{'active':$ctrl.
1499selectedTab === tab.value}\">{{::tab.label}}</button>\n      </div>\n    </div>",
1500    controller: function ($state) {
1501        var $ctrl = this;
1502        this.$onInit = function () {
1503            $ctrl.selectTab = $ctrl.setTab;
1504            $ctrl.tabOptions = _.map($ctrl.tabs, function (tab) { return ({
1505                label: tab.split('-').join(' '),
1506                value: tab,
1507            }); });
1508            if (!$ctrl.selectedTab) {
1509                var tab = $state.params.tab || _.first($ctrl.tabs);
1510                $ctrl.setTab(tab, true);
1511            }
1512        };
1513        this.$onChanges = function (changes) {
1514            if (changes.setTabValue && changes.setTabValue.currentValue) {
1515                $ctrl.selectedTab = changes.setTabValue.currentValue;
1516            }
1517        };
1518        this.setTab = function (tab, firstChange) {
1519            if (tab !== $ctrl.selectedTab) {
1520                if (!firstChange && _.has($ctrl, 'onTabChange')) {
1521                    $ctrl.onTabChange({ tab: tab });
1522                }
1523                $ctrl.selectedTab = tab;
1524            }
1525            if (!$ctrl.disableStateUpdate && _.has($state.params, 'tab')) {
1526                $ctrl.updateState(tab);
1527            }
1528        };
1529        this.updateState = function (tab) {
1530            var currentTab = $state.params.tab;
1531            if (currentTab !== tab) {
1532                $state.params.tab = tab;
1533                $state.transitionTo($state.current, $state.params, { notify: false });
1534            }
1535        };
1536    },
1537});
1538navigationComponents.component('multiStepContainer', {
1539    templateUrl: '/templates/system/components/navigation/multi-step-container.html',
1540    bindings: {
1541        onDone: '&',
1542        modelRef: '=',
1543        kendoWizardOptions: '=?',
1544        kendoWizard: '=?',
1545        currentStep: '=?',
1546        hideStepLabels: '=?',
1547    },
1548    transclude: {
1549        steps: 'steps',
1550    },
1551    controller: function ($element, $scope, $timeout) {
1552        var _this = this;
1553        var $ctrl = this;
1554        this.$onInit = function () {
1555            this.wizardElId = "wizard-".concat($scope.$id);
1556        };
1557        this.getCurrentStepForm = function () {
1558            return _.get($scope.stepContainerForm, $ctrl.currentStep.options.formName, {});
1559        };
1560        this.handleStepValidation = function (event, onValid) {
1561            if (onValid === void 0) { onValid = _.noop; }
1562            var stepForm = $ctrl.getCurrentStepForm();
1563            var isValid = stepForm.$valid;
1564            var skipValidation = event.sender.options.skipValidation;
1565            if (!isValid && !skipValidation)
1566                event.preventDefault();
1567            event.sender.stepper.selectedStep.setValid(isValid);
1568            if (isValid)
1569                return onValid();
1570            event.sender.trigger('formValidateFailed', $ctrl.currentStep);
1571            $timeout(stepForm.$setSubmitted);
1572        };
1573        this.initWizard = function () {
1574            var steps = $ctrl.getSteps();
1575            var wizardConfig = _.defaults($ctrl.kendoWizardOptions, {
1576                linear: true,
1577                done: function (e) {
1578                    $ctrl.handleStepValidation(e, function () { return _.result($ctrl, 'onDone'); });
1579                },
1580                pager: steps.length > 1,
1581                messages: {
1582                    done: 'SUBMIT',
1583                    next: 'NEXT',
1584                    previous: 'PREVIOUS',
1585                },
1586                clearButton: false,
1587                select: function (e) {
1588                    var isNext = $ctrl.currentStep.options.index < e.step.options.index;
1589                    if (isNext)
1590                        $ctrl.handleStepValidation(e);
1591                },
1592                formValidateFailed: function (e) {
1593                    e.preventDefault();
1594                },
1595                activate: function (e) {
1596                    $ctrl.setCurrentStep(e);
1597                },
1598                steps: steps,
1599            });
1600            var element = $("#".concat($ctrl.wizardElId));
1601            element.kendoWizard(wizardConfig);
1602            $ctrl.kendoWizard = element.data('kendoWizard');
1603            $ctrl.currentStep = $ctrl.kendoWizard.currentStep;
1604            if ($ctrl.hideStepLabels || isPhone) {
1605                $ctrl.kendoWizard.stepper.setOptions({ label: false });
1606            }
1607        };
1608        this.$postLink = function () {
1609            $timeout($ctrl.initWizard);
1610        };
1611        this.getSteps = function () {
1612            var stepEls = $element.find('step');
1613            var buttons;
1614            if (_.size(stepEls) === 1)
1615                buttons = ['done'];
1616            return _.map(stepEls, function (step, i) {
1617                var stepElm = angular.element(step);
1618                var label = stepElm.attr('label');
1619                return {
1620                    title: label,
1621                    label: label,
1622                    angularElement: stepElm,
1623                    iconTemplate: stepElm.attr('icon-template'),
1624                    icon: stepElm.attr('icon'),
1625                    formName: "".concat(_.camelCase(label), "Form"),
1626                    content: stepElm.contents(),
1627                    buttons: buttons,
1628                };
1629            });
1630        };
1631        this.setCurrentStep = function (e) {
1632            _this.currentStep = e.step;
1633        };
1634    },
1635});
1636navigationComponents.component('step', {
1637    template: "\n    <div id=\"{{::$ctrl.label}}\">\n      <ng-form name=\"{{$ctrl.formName}}\">\n        <ng-transclude></ng-transclude>\n      </ng-form>\n    </div>\n  ",
1638    transclude: true,
1639    bindings: {
1640        label: '@',
1641        icon: '@?',
1642        iconTemplate: '@?',
1643    },
1644    controller: function ($scope) {
1645        var $ctrl = this;
1646        this.$onInit = function () {
1647            $ctrl.formName = "".concat(_.camelCase($ctrl.label), "Form");
1648        };
1649        this.getForm = function () { return $scope[$ctrl.formName]; };
1650    },
1651});
1652;
1653'use strict';
1654var statsRow = angular.module('resource', []);
1655statsRow.component('resourceListNavigation', {
1656    bindings: {
1657        model: '<',
1658        onTabChange: '&',
1659        onSearchChange: '&',
1660    },
1661    templateUrl: 'templates/system/components/resource-list-navigation.html',
1662    controller: function () {
1663        var $ctrl = this;
1664        $ctrl.$onInit = function () {
1665            $ctrl.states = {
1666                current: false,
1667                past: false,
1668                upcoming: false,
1669            };
1670        };
1671    },
1672});
1673;
1674'use strict';
1675var selectionComponents = angular.module('selectionComponents', []);
1676selectionComponents.component('listSelection', {
1677    bindings: {
1678        list: '<',
1679        selected: '=',
1680        titleKey: '@',
1681        valueKey: '@',
1682        canSelectAll: '<',
1683        isDisabled: '<',
1684        noRequire: '<',
1685    },
1686    templateUrl: 'templates/system/components/list-selection.html',
1687    controller: function ($timeout, $scope) {
1688        var $ctrl = this;
1689        this.selectedIndexes = [];
1690        this.allSelected = false;
1691        this.$onChanges = function (changes) {
1692            if (changes.list &&
1693                !changes.list.previousValue &&
1694                changes.list.currentValue)
1695                getSelected();
1696            if (changes.isDisabled)
1697                handleDisabledChange(changes.isDisabled);
1698        };
1699        function handleDisabledChange(change) {
1700            if (!change.isFirstChange() && change.currentValue)
1701                deselectAll();
1702            else if (!change.isFirstChange() &&
1703                !change.currentValue &&
1704                change.previousValue) {
1705                deselectAll();
1706                updateForm();
1707            }
1708        }
1709        this.addItem = function (index) {
1710            var itemVal = $ctrl.list[index][$ctrl.valueKey];
1711            if ($ctrl.selected.indexOf(itemVal) > -1)
1712                return;
1713            this.selected.push(itemVal);
1714            this.selectedIndexes.push(index);
1715            updateForm();
1716            checkAllSelected();
1717        };
1718        this.removeItem = function (index) {
1719            var itemVal = $ctrl.list[index][$ctrl.valueKey];
1720            this.selected = _.pull(this.selected, itemVal);
1721            this.selectedIndexes = _.pull($ctrl.selectedIndexes, index);
1722            updateForm();
1723            checkAllSelected();
1724        };
1725        this.isChecked = function (index) {
1726            return this.selectedIndexes.length
1727                ? $ctrl.selectedIndexes.indexOf(index) > -1
1728                : false;
1729        };
1730        this.handleCheck = function () {
1731            if (!$ctrl.allSelected)
1732                selectAll();
1733            else
1734                deselectAll();
1735        };
1736        function checkAllSelected() {
1737            $ctrl.allSelected =
1738                $ctrl.list && $ctrl.selectedIndexes.length === $ctrl.list.length;
1739        }
1740        function getSelected() {
1741            if (!$ctrl.selected)
1742                return ($ctrl.selected = []);
1743            _.forEach($ctrl.list, function (item, index) {
1744                doCheck(item, index);
1745            });
1746            checkAllSelected();
1747            updateForm(true);
1748        }
1749        function doCheck(item, index) {
1750            if ($ctrl.selected.indexOf(item[$ctrl.valueKey]) !== -1) {
1751                $ctrl.selectedIndexes.push(index);
1752            }
1753        }
1754        function deselectAll() {
1755            $ctrl.allSelected = false;
1756            $ctrl.selected = [];
1757            $ctrl.selectedIndexes = [];
1758            updateForm();
1759        }
1760        function selectAll() {
1761            $ctrl.selectedIndexes = _.range(0, $ctrl.list.length);
1762            $ctrl.selected = _.map($ctrl.list, $ctrl.valueKey);
1763            $ctrl.allSelected = true;
1764            updateForm();
1765        }
1766        function updateForm(keepClean) {
1767            if (!keepClean)
1768                $scope['listSelection' + $scope.$id].$setDirty();
1769            if (!$ctrl.isDisabled) {
1770                var valid = $ctrl.noRequire ? true : $ctrl.selected.length > 0;
1771                $scope['listSelection' + $scope.$id].$setValidity('required', valid);
1772            }
1773            else if ($ctrl.isDisabled)
1774                $scope['listSelection' + $scope.$id].$setValidity('required', true);
1775        }
1776    },
1777});
1778selectionComponents.component('daySelector', {
1779    template: '<label class="day-select-title" title="Eligible Days">{{ :: $ctrl.label }}</label>' +
1780        '<div class="carpool-days-row form-group" title="Weekly commute schedule">' +
1781        '<button ng-repeat="day in $ctrl.days" class="btn btn-default btn-sm text-uppercase" ng-class="{\'active\': $ctrl.isSelected(day)}" ng-click="$ctrl.toggleDaySelection(day)">{{ :: day }}</button>' +
1782        '</div>',
1783    require: {
1784        ngModel: 'ngModel',
1785    },
1786    bindings: {
1787        label: '<?',
1788        onChange: '&?',
1789    },
1790    controller: function () {
1791        var $ctrl = this;
1792        $ctrl.days = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
1793        $ctrl.$onInit = function () {
1794            $ctrl.label = $ctrl.label || 'ON THESE DAYS OF THE WEEK';
1795            $ctrl.selected = $ctrl.selected || [];
1796            $ctrl.ngModel.$render = function () {
1797                $ctrl.selected = $ctrl.ngModel.$viewValue || $ctrl.selected;
1798            };
1799        };
1800        $ctrl.isSelected = function (day) {
1801            var index = $ctrl.days.indexOf(day) + 1;
1802            return $ctrl.selected.indexOf(index) !== -1;
1803        };
1804        $ctrl.toggleDaySelection = function (day) {
1805            var index = $ctrl.days.indexOf(day) + 1;
1806            if ($ctrl.isSelected(day)) {
1807                $ctrl.selected = $ctrl.selected.filter(function (selectedDay) {
1808                    return selectedDay !== index;
1809                });
1810            }
1811            else {
1812                $ctrl.selected = $ctrl.selected.concat([index]);
1813            }
1814            $ctrl.selected.sort();
1815            $ctrl.ngModel.$setViewValue($ctrl.selected);
1816            if ($ctrl.onChange)
1817                $ctrl.onChange({ selected: $ctrl.selected });
1818        };
1819    },
1820});
1821;
1822'use strict';
1823var statsRow = angular.module('stats', []);
1824statsRow.component('iconStatList', {
1825    bindings: {
1826        models: '<',
1827        columns: '@',
1828    },
1829    templateUrl: 'templates/system/components/icon-stat-list.html',
1830    controller: function () {
1831        var $ctrl = this;
1832        $ctrl.displayFieldIcons = {
1833            Trips: 'road',
1834            Distance: 'route',
1835            'CO2 Saved': 'seedling',
1836            'Money Saved': 'piggy-bank',
1837            'Calories Burned': 'heartbeat',
1838            Points: 'map-marker-alt',
1839        };
1840        $ctrl.dataColumIconMap = {
1841            participants: 'user',
1842            teamCount: 'route',
1843            networkCount: 'networks',
1844            trips: 'trips',
1845            miles: 'distance',
1846            co2Savings: 'plant',
1847            dollarsSavings: 'save',
1848            calories: 'calories',
1849        };
1850        $ctrl.$onInit = function () { };
1851    },
1852});
1853;
1854'use strict';
1855var widgetComponents = angular.module('widgetComponents', []);
1856widgetComponents.component('networkJoinWidget', {
1857    template: "\n    <div class=\"widget achievement-widget mt-15\" ng-if=\"$ctrl.availableProgramNetworks.length\">\n    <div class=\"panel panel-default\">\n      <div class=\"panel-heading border-none\">\n        <h3 class=\"bold text-center text-uppercase\">{{ ::$ctrl.title }}</h3>\n      </div>\n      <div class=\"panel-body bg-white\" style=\"border-radius: 4px;\">\n        <div class=\"px-15\">\n          {{ ::$ctrl.description }}\n        </div>\n\n        <div ng-repeat=\"network in $ctrl.availableProgramNetworks\" class=\"d-flex justify-content-center p-15\">\n          <img src=\"{{network.logoURL}}\" alt=\"network logo\" style=\"max-width: 50%; height: auto;\">\n        </div>\n      </div>\n      <div class=\"panel-footer no-border-top text-center\" style=\"background-color: #ffffff\">\n        <a class=\"btn btn-primary text-uppercase pt-6\" href ui-sref=\"account.edit.networks\">LEARN MORE</a>\n      </div>\n    </div>\n  </div>\n  ",
1858    controller: function (vSession, CONFIG, $vhttp) {
1859        var $ctrl = this;
1860        this.$onInit = function () {
1861            if (!_.get(CONFIG, 'premiumNetworks.multiPrimaryNetworkEnabled')) {
1862                return;
1863            }
1864            this.bindContent();
1865            this.bindNetworks();
1866        };
1867        this.bindContent = function () {
1868            this.title = _.get(CONFIG, 'regionalNetworkWidgetLanguage.title');
1869            this.description = _.get(CONFIG, 'regionalNetworkWidgetLanguage.description');
1870        };
1871        this.bindNetworks = function () {
1872            $vhttp
1873                .get('/api/v1/users/' + vSession.user._id + '/available-programs')
1874                .then(function (res) {
1875                $ctrl.availableProgramNetworks = res;
1876            })
1877                .catch(_.noop);
1878        };
1879    },
1880});
1881;
1882'use strict';
1883var appNavbar = angular.module('appNavbar', []);
1884appNavbar.directive('navbarManageList', function ($state, $rootScope, SessionUserDataService, EnabledTools) {
1885    return {
1886        restrict: 'A',
1887        scope: {},
1888        templateUrl: '/templates/navbar/navbar-manage-list.html',
1889        link: function ($scope) {
1890            var parentStates = EnabledTools.getParentStates(), rootWatch = null, networkWatch = null, authorization = null;
1891            init();
1892            function init() {
1893                asyncSetup();
1894            }
1895            function asyncSetup() {
1896                authorization = $rootScope.$watch('authorizationPending', function (newValue, oldValue) {
1897                    if (newValue != oldValue) {
1898                        authorization();
1899                        syncSetup();
1900                    }
1901                });
1902            }
1903            function syncSetup() {
1904                $scope.enabledTools = EnabledTools.getCategories();
1905                setup();
1906            }
1907            function setup() {
1908                if (!_.isEmpty($scope.enabledTools)) {
1909                    setupNetworkWatcher();
1910                    if (SessionUserDataService.user.isAdmin &&
1911                        $scope.enabledTools.tool) {
1912                        $scope.enabledTools.tool.unshift(getAdminDashboard());
1913                        $scope.tracesEnabled = canDebug();
1914                    }
1915                }
1916                setColSize();
1917                stateHandler({}, $state.current);
1918                setupRootWatcher();
1919            }
1920            function setupRootWatcher() {
1921                rootWatch = $rootScope.$on('$stateChangeStart', stateHandler);
1922            }
1923            function canDebug() {
1924                if (window.CONFIG.tracesDebugEnabled) {
1925                    var validEmailDomain = window.CONFIG.debugEmailDomain;
1926                    var email = SessionUserDataService.user && SessionUserDataService.user.email;
1927                    var domain = email.split('@')[1];
1928                    return domain === validEmailDomain;
1929                }
1930                return false;
1931            }
1932            function stateHandler(event, toState, toParams, fromState, fromParams) {
1933                $scope.activeState = toState.name;
1934                $scope.isActiveChildState =
1935                    parentStates.indexOf(getParentState($scope.activeState)) > -1;
1936            }
1937            function setupNetworkWatcher() {
1938                if (CONFIG.hideNetworkManageMenu) {
1939                    return;
1940                }
1941                networkWatch = $scope.$watch(function () {
1942                    return SessionUserDataService.managednetworks;
1943                }, function (newValue, oldValue) {
1944                    if (!newValue && !oldValue)
1945                        return;
1946                    if (newValue.length) {
1947                        setNetworkManage();
1948                        setColSize();
1949                        networkWatch();
1950                    }
1951                });
1952            }
1953            function setNetworkManage() {
1954                $scope.enabledTools.networkmanage = [
1955                    getNetworkManage(),
1956                    getNetworkDashboard(),
1957                ];
1958            }
1959            function getParentState(fullStateName) {
1960                return fullStateName.slice(0, fullStateName.indexOf('.'));
1961            }
1962            function getNetworkManage() {
1963                return {
1964                    adminEnabled: true,
1965                    name: 'View All',
1966                    baseRoute: 'reporting.network.managed-networks',
1967                    category: 'networkmanage',
1968                    description: 'Dashboard overview of admin features',
1969                    entryPointRoute: 'reporting.network.managed-networks',
1970                };
1971            }
1972            function getNetworkDashboard() {
1973                var defaultItem = {
1974                    name: 'Management Dashboard',
1975                    description: 'Networks, Reports, and more',
1976                    showDescription: true,
1977                    baseRoute: 'premium.dashboard',
1978                    entryPointRoute: 'premium.dashboard.home',
1979                    adminEnabled: false,
1980                    networkAdminEnabled: true,
1981                };
1982                var def = _.find(CONFIG.toolsMenuMega, { name: defaultItem.name });
1983                return def || defaultItem;
1984            }
1985            function getAdminDashboard() {
1986                return {
1987                    adminEnabled: true,
1988                    name: 'Admin Dashboard',
1989                    baseRoute: 'admin.dashboard',
1990                    category: 'tool',
1991                    description: 'Dashboard overview of admin features',
1992                    entryPointRoute: 'admin.dashboard',
1993                };
1994            }
1995            function setColSize() {
1996                $scope.colSize = ~~(12 / Object.keys($scope.enabledTools).length);
1997            }
1998            $scope.$on('$destroy', function () {
1999                if (networkWatch)
2000                    networkWatch();
2001                if (rootWatch)
2002                    rootWatch();
2003                rootWatch = networkWatch = null;
2004            });
2005        },
2006    };
2007});
2008appNavbar.directive('navbarListItem', function (SessionUserDataService) {
2009    return {
2010        restrict: 'A',
2011        scope: {
2012            enabled: '=',
2013            name: '=',
2014            isActiveState: '=',
2015            canDebug: '=',
2016        },
2017        template: "<ul class=\"list-container-list\">\n      <li class=\"list-item dropdown-header\" ng-if=\":: lookup[name]\">{{ :: lookup[name] }}</li>\n      <li class=\"list-item\" ng-repeat=\"tool in enabled\">\n        <a ng-if=\"!tool.customLink\" class=\"item-link\" href analytics-on ui-sref=\"{{tool.entryPointRoute}}\"\n          data-description=\"{{:: tool.description}}\"\n          ng-class=\"{ active : isActiveState === tool.entryPointRoute }\">{{:: tool.name}}
2017\n          <span ng-if=\"tool.showDescription\" aria-hidden=\"true\"><br><em><small>{{:: tool.description}}</small></em></span>\n        </a>\n        <a ng-if=\"tool.customLink\" class=\"item-link\" ng-href=\"{{tool.customLink}}\" target=\"{{target = tool.target || '_blank'}}\" analytics-on\n          data-description=\"{{:: tool.description}}\">{{:: tool.name}}\n          <span ng-if=\"tool.showDescription\"><br><em><small>{{:: tool.description}}</small></em></span>\n        </a>\n      </li>\n      <li class=\"list-item\" ng-if=\"showTraces\">\n        <a class=\"item-link\" href=\"/app/traces/dashboard\">Traces Debugger</a>\n      </li>\n    </ul>\n    <navbar-my-networks-item user-networks=\"managednetworks\" ng-if=\"showNetworks\"></navbar-my-networks-item>",
2018        link: function ($scope) {
2019            $scope.lookup = {
2020                program: 'programs',
2021                systemreport: 'System Reports',
2022                networkmanage: 'Network Manage',
2023                tool: 'tools',
2024                mynetworks: 'My Networks',
2025                moretools: ' ',
2026            };
2027            $scope.managednetworks = SessionUserDataService.managednetworks;
2028            $scope.showNetworks =
2029                $scope.name === 'networkmanage' && $scope.managednetworks.length;
2030            $scope.showTraces = $scope.canDebug && $scope.name === 'tool';
2031        },
2032    };
2033});
2034appNavbar.directive('navbarMyNetworksItem', function ($state, $filter) {
2035    return {
2036        restrict: 'EA',
2037        scope: {
2038            userNetworks: '=',
2039        },
2040        template: '<div class="divider"></div>' +
2041            '<ul class="list-container-list" style="max-height: 250px; overflow-y: auto;">' +
2042            '<li class="list-item dropdown-header">My Networks</li>' +
2043            '<li class="list-item" ng-repeat="tool in networkData">' +
2044            '<a class="item-link" href analytics-on ui-sref="networkadmin.overview({network:tool._id})"' +
2045            'data-description="{{tool.description}}"' +
2046            'ng-class="{ active: $state.includes(tool.entryPointRoute) }">{{:: tool.name}}' +
2047            '<small class="text-muted" ng-if="tool.ancestors.length"' +
2048            'ng-repeat="ancestor in tool.ancestors"><br><i>{{:: ancestor.name}}</i>' +
2049            '</small>' +
2050            '</a>' +
2051            '</li>' +
2052            '</ul>',
2053        link: function ($scope) {
2054            $scope.networkData = $filter('orderBy')($scope.userNetworks, 'name');
2055        },
2056    };
2057});
2058appNavbar.directive('navbarProgramList', function ($state, $rootScope, EnabledPrograms) {
2059    return {
2060        restrict: 'A',
2061        scope: {},
2062        templateUrl: '/templates/navbar/navbar-program-list.html',
2063        link: function ($scope) {
2064            $scope.programs = new EnabledPrograms();
2065            $scope.colSize = ~~(12 / $scope.programs.length);
2066            stateHandler({}, $state.current, $state.params);
2067            function stateHandler(event, toState, toParams, fromState, fromParams) {
2068                $scope.activeState = toParams.tab
2069                    ? buildQueryStringUrl(toState.name, 'tab', toParams.tab)
2070                    : toState.name;
2071                $scope.isActiveChildState =
2072                    $scope.activeState === 'challenges.list' ||
2073                        $scope.activeState === "incentives.list({tab:'available'})" ||
2074                        $scope.activeState === "incentives.list({tab:'points'})";
2075            }
2076            function buildQueryStringUrl(name, key, value) {
2077                return name + '({' + key + ':' + "\'" + value + "\'" + '})';
2078            }
2079            $rootScope.$on('$stateChangeStart', stateHandler);
2080        },
2081    };
2082});
2083appNavbar.directive('programListItem', function () {
2084    return {
2085        restrict: 'A',
2086        scope: {
2087            program: '=',
2088            isActiveState: '=',
2089        },
2090        template: '<ul class="list-container-list text-center">' +
2091            '<li class="list-item program">' +
2092            '<a class="item-link"' +
2093            'ng-class="{ active : isActiveState === program.entryPoint }"' +
2094            'ng-if="program.link" ng-href="{{:: program.link}}">' +
2095            '<img ng-src="{{:: program.img }}" ng-if="program.img">
2095' +
2096            '<h2 class="dropdown-header">{{:: program.header}}</h2><span ng-bind-html="program.paragraph"></span>' +
2097            '<button class="btn btn-small btn-info" ng-if="program.entryPoint && !program.static">{{:: program.buttonText}}</button>' +
2098            '</a>' +
2099            '<a class="item-link"' +
2100            'ng-class="{ active : isActiveState === program.entryPoint }"' +
2101            'ng-if="!program.link" ui-sref="{{:: program.entryPoint}}">' +
2102            '<img ng-src="{{:: program.img }}" ng-if="program.img">' +
2103            '<h2 class="dropdown-header">{{:: program.header}}</h2><span ng-bind-html="program.paragraph"></span>' +
2104            '<button class="btn btn-small btn-info" ng-if="program.entryPoint && !program.static">{{:: program.buttonText}}</button>' +
2105            '</a>' +
2106            '</li></ul>',
2107        link: function ($scope) { },
2108    };
2109});
2110;
2111'use strict';
2112var appDirectives = angular.module('appDirectives', ['appNavbar']);
2113appDirectives.directive('debounceClick', function ($timeout) {
2114    return {
2115        restrict: 'A',
2116        link: function ($scope, $element, $attrs) {
2117            var orgContent;
2118            bindEvents();
2119            function bindEvents() {
2120                $element.bind('click', function () {
2121                    if ($attrs.pendingText) {
2122                        orgContent = $element.text();
2123                        $element.text($attrs.pendingText);
2124                    }
2125                    $element.attr('disabled', true);
2126                    $timeout(rollbackElement, $attrs.duration || 500);
2127                });
2128            }
2129            function rollbackElement() {
2130                $element.attr('disabled', false);
2131                if ($attrs.pendingText) {
2132                    $element.text(orgContent);
2133                }
2134            }
2135        },
2136    };
2137});
2138appDirectives.directive('toggleContrast', function ($localstorage) {
2139    return {
2140        restrict: 'A',
2141        link: function ($scope, $elem, $attrs) {
2142            $scope.contrastEnabled = getPreference();
2143            $(document).ready(function () {
2144                if ($scope.contrastEnabled)
2145                    turnOn();
2146                else
2147                    turnOff();
2148            });
2149            $elem.on('click', toggleContrast);
2150            function toggleContrast() {
2151                if ($scope.contrastEnabled)
2152                    turnOff();
2153                else
2154                    turnOn();
2155                $scope.$apply(function () {
2156                    $scope.contrastEnabled = !$scope.contrastEnabled;
2157                });
2158                storePreference();
2159            }
2160            function getPreference() {
2161                return ($localstorage.get('highContrastEnabled', 'disabled') === 'enabled');
2162            }
2163            function storePreference() {
2164                $localstorage.set('highContrastEnabled', $scope.contrastEnabled ? 'enabled' : 'disabled');
2165            }
2166            function turnOn() {
2167                $('body').addClass('high-contrast');
2168            }
2169            function turnOff() {
2170                $('body').removeClass('high-contrast');
2171            }
2172        },
2173    };
2174});
2175appDirectives.directive('roundNumberSmart', function () {
2176    return {
2177        require: 'ngModel',
2178        restrict: 'A',
2179        link: function ($scope, $elem, $attrs, $ctrl) {
2180            var ngModelCtrl = $ctrl, _keyUpHandler = _.debounce(handleUp, 600);
2181            ngModelCtrl.$formatters.push(function (value) {
2182                return value || 1;
2183            });
2184            ngModelCtrl.$parsers.unshift(function (value) {
2185                if (value && isNumber(value) && isDecimal(value)) {
2186                    value = parseFloat(value).toFixed(2);
2187                }
2188                else {
2189                    value = ~~value;
2190                }
2191                ngModelCtrl.$setViewValue(value);
2192                return value;
2193            });
2194            function handleUp() {
2195                var value = parseFloat(ngModelCtrl.$viewValue), domValue = $elem.val();
2196                if (domValue && parseFloat(domValue) !== value) {
2197                    $elem.val(ngModelCtrl.$viewValue);
2198                }
2199            }
2200            function isNumber(value) {
2201                return typeof value === 'number' || !Number.isNaN(parseFloat(value));
2202            }
2203            function isDecimal(value) {
2204                return value % 1 !== 0;
2205            }
2206            $elem.on('keyup', _keyUpHandler);
2207            $scope.$on('$destroy', function () {
2208                $elem.off('keyup', _keyUpHandler);
2209            });
2210        },
2211    };
2212});
2213appDirectives.directive('scrollSpy', function ($timeout, elementHelper) {
2214    return {
2215        restrict: 'A',
2216        scope: {
2217            customClass: '@',
2218            triggerOffset: '=?',
2219        },
2220        link: function ($scope, $element, $attrs) {
2221            var spies = [];
2222            var $window = $(window);
2223            var currentIndex = 0;
2224            var loading = true;
2225            $scope.customClass = $scope.customClass ? $scope.customClass : 'active';
2226            $(document).ready(function () {
2227                $timeout(init, 300);
2228            });
2229            function init() {
2230                changeDetection();
2231                $window.on('scroll', handler);
2232            }
2233            function handler() {
2234                if (!elementHelper.isOnSmallScreen()) {
2235                    findSpy();
2236                }
2237            }
2238            function getScrollPos() {
2239                return ($(window).scrollTop() +
2240                    elementHelper.getNavHeight() +
2241                    ($scope.triggerOffset || 100));
2242            }
2243            function findSpy() {
2244                if (!loading && spies.length) {
2245                    if (!$window)
2246                        return;
2247                    var scrollPos = getScrollPos();
2248                    if (scrollPos < spies[0].offsetTop && currentIndex !== 0) {
2249                        toggleHighlight(0, currentIndex);
2250                    }
2251                    else if (elementHelper.isScrolledBtm(20)) {
2252                        toggleHighlight(spies.length - 1, currentIndex);
2253                    }
2254                    else if (spies.length > 3 &&
2255                        getElementHeight(spies.length - 1) +
2256                            getElementHeight(spies.length - 2) <
2257                            $window.height() &&
2258                        elementHelper.isScrolledBtm(200)) {
2259                        toggleHighlight(spies.length - 2, currentIndex);
2260                    }
2261                    else {
2262                        rotateThrough(scrollPos);
2263                    }
2264                }
2265            }
2266            function toggleHighlight(add, remove) {
2267                removeClass(remove);
2268                addClass(add);
2269            }
2270            function getElementHeight(index) {
2271                return spies[index]
2272                    ? spies[index].elementBottom - spies[index].elementTop
2273                    : 0;
2274            }
2275            function rotateThrough(scrollPos) {
2276                _.forEach(spies, function (spy, index) {
2277                    if ((scrollPos >= spy.elementTop && index === spies.length - 1) ||
2278                        (spies.length > 1 && scrollPos < spies[index + 1].elementTop)) {
2279                        toggleHighlight(index, currentIndex);
2280                        return false;
2281                    }
2282                });
2283            }
2284            function getSpies() {
2285                spies = _.sortBy(_.map($('div[spy]'), function (spy) {
2286                    return {
2287                        element: spy,
2288                        targetId: spy.getAttribute('spy'),
2289                        elementTop: $(spy).offset().top,
2290                        elementBottom: $(spy).offset().top + $(spy).outerHeight(),
2291                    };
2292                }), 'elementTop');
2293            }
2294            function addClass(index) {
2295                var el = spies[index]
2296                    ? document.getElementById(spies[index].targetId)
2297                    : null;
2298                if (el) {
2299                    currentIndex = index;
2300                    el.classList.add($scope.customClass);
2301                }
2302                else {
2303                    console.warn('spy element not found index:', index);
2304                }
2305            }
2306            function removeClass(index) {
2307                var el = spies[index]
2308                    ? document.getElementById(spies[index].targetId)
2309                    : null;
2310                if (el) {
2311                    el.classList.remove($scope.customClass);
2312                }
2313                else {
2314                    console.warn('spy element not found index:', index);
2315                }
2316            }
2317            var debounceChange = _.debounce(changeDetection, 300);
2318            function changeDetection() {
2319                getSpies();
2320                loading = false;
2321                findSpy();
2322            }
2323            function handleSpy() {
2324                if (!loading) {
2325                    loading = true;
2326                    debounceChange();
2327                }
2328            }
2329            var newSpy = $scope.$on('newSpy', handleSpy);
2330            var downSpy = $scope.$on('spyDown', handleSpy);
2331            $scope.$on('$destroy', function () {
2332                $window.off('scroll', handler);
2333                newSpy();
2334                downSpy();
2335                debounceChange = spies = $window = currentIndex = loading = null;
2336            });
2337        },
2338    };
2339});
2340appDirectives.directive('spy', function ($timeout, $rootScope) {
2341    return {
2342        restrict: 'A',
2343        link: function ($scope, $element, $attrs) {
2344            $rootScope.$broadcast('newSpy');
2345            $scope.$on('$destroy', function () {
2346                $rootScope.$broadcast('spyDown');
2347            });
2348        },
2349    };
2350});
2351appDirectives.directive('stickyOnScroll', function ($timeout) {
2352    return {
2353        restrict: 'A',
2354        link: function ($scope, $element, $attrs) {
2355            var plane = null;
2356            var $window = null;
2357            var db = null;
2358            var resizeFn = null;
2359            var deRegisterFn = null;
2360            var outOfViewFn = null;
2361            var inViewFn = null;
2362            init();
2363            function init() {
2364                $window = $(window);
2365                plane = getPlane($window, $element);
2366                outOfViewFn = $attrs.fromOffScreen ? 'isOffScreen' : 'isAtPlaneEdge';
2367                inViewFn = $attrs.fromOffScreen
2368                    ? 'isOnScreen'
2369                    : 'isScrolledToElementCoordinates';
2370                if (!resizeFn) {
2371                    resizeFn = $timeout(function () {
2372                        db = _.debounce(resize, 300);
2373                        $window.on('resize', db);
2374                    });
2375                }
2376                if (plane.isOnSmallScreen()) {
2377                    return;
2378                }
2379                $element.css('transition', 'top .8s linear');
2380                if (!deRegisterFn) {
2381                    deRegisterFn = $timeout(function () {
2382                        $window.on('scroll', checkVisibility);
2383                    });
2384                }
2385            }
2386            function destroyEventHandlers() {
2387                $window.off('scroll', checkVisibility);
2388                $window.off('resize', db);
2389            }
2390            function resize() {
2391                if (plane.element.manipulated) {
2392                    if (plane.element.hasMoved) {
2393                        removeSticky($element);
2394                    }
2395                }
2396                resetVars();
2397                init();
2398            }
2399            function checkVisibility() {
2400                if (plane.element[outOfViewFn]()) {
2401                    plane.element.move(setSticky.bind(this, $element));
2402                }
2403                else {
2404                    if (plane.element.hasMoved) {
2405                        if (plane.element[inViewFn]()) {
2406                            plane.element.move(removeSticky.bind(this, $element));
2407                        }
2408                    }
2409                }
2410            }
2411            function setSticky($el) {
2412                $el
2413                    .css('width', plane.element.computed['width'])
2414                    .css('right', plane.element.distanceFromRightViewport())
2415                    .css('position', 'fixed')
2416                    .css('top', plane.element.toTop() + 5);
2417            }
2418            function removeSticky($el) {
2419                $el
2420                    .css('width', '')
2421                    .css('right', '')
2422                    .css('position', '')
2423                    .css('top', '');
2424            }
2425            function resetVars() {
2426                $window = outOfViewFn = inViewFn = plane = null;
2427            }
2428            function top() {
2429                var nav = $('.navbar'), sub = nav.parent().find('.subsite-navbar'), top = ~~(nav.outerHeight() + sub.outerHeight());
2430                nav = sub = null;
2431                return top;
2432            }
2433            function getPlane($window, $element) {
2434                return {
2435                    element: {
2436                        computed: window.getComputedStyle($element[0]),
2437                        coordinates: {},
2438                        getCoordinates: function () {
2439                            this.coordinates = $element[0].getBoundingClientRect();
2440                            this.coordinates.y = this.coordinates.y || this.coordinates.top;
2441                        },
2442                        hasMoved: false,
2443                        manipulated: false,
2444                        toTop: _.memoize(top),
2445                        _private: {
2446                            getIntFromStyleProperty: function (str) {
2447                                return parseInt(str.slice(0, -2));
2448                            },
2449                        },
2450                        isOffScreen: function () {
2451                            this.getCoordinates();
2452                            return (this.coordinates.y + ~~(this.coordinates.height / 2) <
2453                                this.toTop());
2454                        },
2455                        isAtPlaneEdge: function () {
2456                            this.getCoordinates();
2457                            return ~~this.coordinates.y <= this.toTop();
2458                        },
2459                        isScrolledToElementCoordinates: function () {
2460                            this.getCoordinates();
2461                            return $window.scrollTop() < this.coordinates.y;
2462                        },
2463                        isOnScreen: function () {
2464                            this.getCoordinates();
2465                            return ($window.scrollTop() <
2466                                this.coordinates.height + this.coordinates.y);
2467                        },
2468                        move: function (cb) {
2469                            this.hasMoved = !this.hasMoved;
2470                            this.manipulated = true;
2471                            cb();
2472                        },
2473                        distanceFromRightViewport: function () {
2474                            var right = $window.width() -
2475                                ($element.offset().left + $element.outerWidth());
2476                            return (Math.round(right) -
2477                                this._private.getIntFromStyleProperty(this.computed['marginRight']));
2478                        },
2479                    },
2480                    isOnSmallScreen: function () {
2481                        return $window.innerWidth() < 992;
2482                    },
2483                };
2484            }
2485            function destroyWatchers() {
2486                deRegisterFn = null;
2487                resizeFn = null;
2488                db = null;
2489            }
2490            $element.on('$destroy', function () {
2491                if (deRegisterFn && _.isFunction(deRegisterFn))
2492                    deRegisterFn();
2493                if (resizeFn && _.isFunction(resizeFn))
2494                    resizeFn();
2495                destroyEventHandlers();
2496                destroyWatchers();
2497                resetVars();
2498            });
2499        },
2500    };
2501});
2502appDirectives.directive('autoViewHeight', function ($window, elementHelper) {
2503    return {
2504        link: function (scope, element, attrs) {
2505            setHeight();
2506            function setHeight() {
2507                var height = $window.innerHeight - elementHelper.getNavHeight() + 'px';
2508                element.css('height', height);
2509            }
2510            var handler = _.debounce(setHeight, 300);
2511            _.defer(function () { return angular.element($window).on('resize', handler); }, 300);
2512            var cleanup = function () { return angular.element($window).off('resize', handler); };
2513            scope.$on('$destroy', cleanup);
2514        },
2515    };
2516});
2517appDirectives.directive('commuteHubEmbeddedView', function ($window, elementHelper, CONFIG) {
2518    return {
2519        restrict: 'A',
2520        link: function (scope, element, attrs) {
2521            var originalInnerBodyMinHeight;
2522            var originalBodyOverflow;
2523            $(element).ready(setLayout);
2524            function setLayout() {
2525                var navHeight = elementHelper.getNavHeight();
2526                var footerHeight = elementHelper.getFooterHeight();
2527                var heightAdjustment = CONFIG.commuteHubEmbeddedViewHeightAdjustment || 0;
2528                var height = $window.innerHeight;
2529                var innerBody = $('#innerBody');
2530                if (!originalInnerBodyMinHeight) {
2531                    originalInnerBodyMinHeight = innerBody.css('min-height');
2532                }
2533                var minHeight = 300;
2534                var availableHeight = height - (navHeight + footerHeight) - heightAdjustment;
2535                var finalHeight = Math.max(minHeight, availableHeight);
2536                innerBody.css('min-height', height - navHeight - heightAdjustment + 'px');
2537                var body = $('body');
2538                if (!originalBodyOverflow) {
2539                    originalBodyOverflow = body.css('overflow');
2540                    body.css('overflow', 'hidden');
2541                }
2542                var width = $window.innerWidth + 'px';
2543                element.css({
2544                    position: 'fixed',
2545                    top: navHeight + 'px',
2546                    bottom: footerHeight + 'px',
2547                    height: finalHeight + 'px',
2548                    width: width,
2549                    border: 0,
2550                });
2551            }
2552            var handler = _.debounce(setLayout, 300);
2553            _.defer(function () { return angular.element($window).on('resize', handler); }, 300);
2554            var cleanup = function () {
2555                angular.element($window).off('resize', handler);
2556                var innerBody = $('#innerBody');
2557                var body = $('body');
2558                if (originalInnerBodyMinHeight && innerBody) {
2559                    innerBody.css('min-height', originalInnerBodyMinHeight);
2560                }
2561                if (originalBodyOverflow && body) {
2562                    body.css('overflow', originalBodyOverflow);
2563                }
2564            };
2565            scope.$on('$destroy', cleanup);
2566        },
2567    };
2568});
2569appDirectives.directive('displayAsDollars', function () {
2570    return {
2571        require: 'ngModel',
2572        restrict: 'A',
2573        link: function ($scope, $elem, $attrs, $ctrl) {
2574            $ctrl.$formatters.unshift(function (val) {
2575                return (parseInt(val) / 100).toFixed(2);
2576            });
2577            $ctrl.$parsers.unshift(function (val) {
2578                val = parseFloat(val);
2579                return parseInt(val * 100);
2580            });
2581        },
2582    };
2583});
2584appDirectives.directive('rotateImage', function () {
2585    return {
2586        scope: {
2587            rotateImage: '=',
2588        },
2589        restrict: 'A',
2590        link: function (scope, $elem, $attr) {
2591            var rotate_factor = 0;
2592            scope.rotateImage = function () {
2593                rotate_factor += 1;
2594                var rotate_angle = (90 * rotate_factor) % 360;
2595                $elem[0].style.transform = "rotate(".concat(rotate_angle, "deg)");
2596            };
2597        },
2598    };
2599});
2600appDirectives.directive('pwaModalCloseHandler', function ($rootScope) {
2601    return {
2602        restrict: 'A',
2603        link: function (scope, $elem, $attr) {
2604            var handleEvent = function (e) {
2605                if (window.location.origin !== e.origin)
2606                    return false;
2607                if (e.data === 'closeApp') {
2608                    removeEventListener();
2609                    $rootScope.globalModalHide();
2610                }
2611            };
2612            var removeEventListener = function () {
2613                return window.removeEventListener('message', handleEvent, false);
2614            };
2615            window.addEventListener('message', handleEvent, false);
2616            $rootScope.$on('modalHidden', function () {
2617                removeEventListener();
2618            });
2619        },
2620    };
2621});
2622appDirectives.directive('iframeResizeInjector', function () {
2623    return {
2624        restrict: 'A',
2625        scope: {
2626            onDestroy: '&?',
2627            resizerOptions: '=',
2628        },
2629        link: function (scope, $elem, $attr) {
2630            var parentScriptEl = createScriptEl('iframeResizer.min.js');
2631            var childScriptEl = createScriptEl('iframeResizer.contentWindow.min.js');
2632            function loadResize() {
2633                $elem.append(parentScriptEl);
2634            }
2635            function createScriptEl(file) {
2636                var script = document.createElement('script');
2637                script.src = "/js/libs/iframe-resizer-4.3.2/".concat(file);
2638                return script;
2639            }
2640            $(document).ready(function () {
2641                if (!window.iFrameResize)
2642                    loadResize();
2643                var iframeEl = $($elem[0].querySelector('iframe'));
2644                iframeEl.on('load', function (event) {
2645                    $(this).contents().find('body')[0].append(childScriptEl);
2646                    var iframeId = event.target.id ? "#".concat(event.target.id) : null;
2647                    var options = _.isObject(scope.resizerOptions)
2648                        ? scope.resizerOptions
2649                        : { log: false, heightCalculationMethod: 'lowestElement' };
2650                    new iFrameResize(options, iframeId);
2651                    if (scope.onDestroy) {
2652                        scope.$on('$destroy', function () { return _.result(scope, 'onDestroy'); });
2653                    }
2654                });
2655            });
2656        },
2657    };
2658});
2659appDirectives.directive('dynamicContent', function ($compile, $filter, ContentManagementService) {
2660    return {
2661        restrict: 'A',
2662        link: function (scope, element, attrs) {
2663            var contentWatcher = null;
2664            var contentKey;
2665            var observer = attrs.$observe('dynamicContent', function (value) {
2666                if (!value || value === contentKey)
2667                    return;
2668                contentKey = value;
2669                if (ContentManagementService.isLoaded()) {
2670                    applyContent();
2671                    return;
2672                }
2673                listenForContent();
2674            });
2675            function listenForContent() {
2676                if (contentWatcher)
2677                    return;
2678                contentWatcher = scope.$watch(function () {
2679                    return ContentManagementService.isLoaded();
2680                }, function (loaded) {
2681                    if (loaded) {
2682                        applyContent();
2683                        destroyContentWatcher();
2684                    }
2685                });
2686            }
2687            function destroyContentWatcher() {
2688                observer();
2689                if (!contentWatcher)
2690                    return;
2691                contentWatcher();
2692                contentWatcher = null;
2693            }
2694            function applyContent() {
2695                var content = ContentManagementService.getContent(contentKey);
2696                if (content) {
2697                    var markdown = $filter('markdownToHTML')(content);
2698                    element.html(markdown.toString());
2699                    $compile(element.contents())(scope);
2700                }
2701            }
2702            scope.$on('$destroy', destroyContentWatcher);
2703        },
2704    };
2705});
2706appDirectives.directive('kCheckboxGroup', [
2707    '$timeout',
2708    function ($timeout) {
2709        return {
2710            require: 'ngModel',
2711            scope: {
2712                items: '=',
2713                kOptions: '=',
2714            },
2715            link: function (scope, element, attrs, ngModelCtrl) {
2716                $timeout(function () {
2717                    var kOptions = _.defaults(scope.kOptions, {
2718                        layout: 'vertical',
2719                        inputName: attrs.inputName,
2720                        items: scope.items,
2721                    });
2722                    var checkboxGroup = $(element)
2723                        .kendoCheckBoxGroup(__assign(__assign({}, kOptions), { change: function (e) {
2724                            var checkedItems = this.value();
2725                            $timeout(function () {
2726                                ngModelCtrl.$setViewValue(checkedItems);
2727                            });
2728                        } }))
2729                        .data('kendoCheckBoxGroup');
2730                    ngModelCtrl.$render = function () {
2731                        $timeout(function () {
2732                            checkboxGroup.value(ngModelCtrl.$viewValue || []);
2733                        }, 0);
2734                    };
2735                    ngModelCtrl.$render();
2736                }, 0);
2737            },
2738        };
2739    },
2740]);
2741appDirectives.directive('validateIsNgOption', function ($parse, $timeout) {
2742    return {
2743        require: 'ngModel',
2744        link: function (scope, element, attrs, ngModel) {
2745            var ngOptions = attrs.ngOptions;
2746            var match = ngOptions.match(/^\s*(.+?)\s+as\s+(.+?)\s+for\s+(.+?)\s+in\s+(.+?)(\s+\|\s+.+)?\s*$/);
2747            if (!match) {
2748                throw new Error('Expected ng-options in form of "_select_ as _label_ for _value_ in _collection_ | _filter_" but got "' +
2749                    ngOptions +
2750                    '".');
2751            }
2752            var valueFn = $parse(match[1]);
2753            var collectionFn = $parse(match[4]);
2754            var filterExpr = match[5] ? match[5].trim().substring(2) : null;
2755            var filteredCollectionFn = filterExpr
2756                ? $parse("".concat(match[4], " | ").concat(filterExpr))
2757                : collectionFn;
2758            function getOptions() {
2759                var collection = filteredCollectionFn(scope);
2760                if (!collection)
2761                    return [];
2762                return collection.map(function (item) {
2763                    var _a;
2764                    return valueFn(scope, (_a = {}, _a[match[3]] = item, _a));
2765                });
2766            }
2767            function validate(modelValue) {
2768                if (!modelValue)
2769                    return true;
2770                var options = getOptions();
2771                var isValid = options.includes(modelValue);
2772                ngModel.$setValidity('validOption', isValid);
2773                return isValid;
2774            }
2775            ngModel.$validators.validOption = validate;
2776            ngModel.$viewChangeListeners.push(function () {
2777                ngModel.$validate();
2778            });
2779            scope.$evalAsync(function () {
2780                if (!ngModel.$validate()) {
2781                    ngModel.$setTouched();
2782                }
2783            });
2784            scope.$watchCollection(function () {
2785                return filteredCollectionFn(scope);
2786            }, function (newOptions) {
2787                ngModel.$validate();
2788            });
2789        },
2790    };
2791});
2792;
2793'use strict';
2794var appFilters = angular.module('currencyFilters', []);
2795appFilters.filter('currencySmart', function (CONFIG) {
2796    var currencyConversionRate = CONFIG.currencyConversionRate
2797        ? CONFIG.currencyConversionRate
2798        : 1;
2799    var currencyFormat = CONFIG.currencyFormat
2800        ? CONFIG.currencyFormat
2801        : '$#VALUE#';
2802    return function (input) {
2803        if (!angular.isNumber(input) || isNaN(input))
2804            return null;
2805        var dollars = input.toFixed(2);
2806        var value = dollars * currencyConversionRate;
2807        return currencyFormat.replace('#VALUE#', value
2808            .toFixed(2)
2809            .toString()
2810            .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'));
2811    };
2812});
2813;
2814'use strict';
2815var appFilters = angular.module('dateFilters', []);
2816appFilters.factory('formatIsoDateToShortDate', function () {
2817    return function formatIsoDateToShortDate(isoString) {
2818        var d = new Date(isoString);
2819        if (isNaN(d.getTime())) {
2820            return null;
2821        }
2822        var month = String(d.getUTCMonth() + 1).padStart(2, '0');
2823        var day = String(d.getUTCDate()).padStart(2, '0');
2824        var year = String(d.getUTCFullYear()).slice(-2);
2825        return month + '/' + day + '/' + year;
2826    };
2827});
2828appFilters.filter('ordinalDate', function ($log) {
2829    $log.getInstance('ordinalDate');
2830    return function (input) {
2831        var date = new Date(input);
2832        date = moment(date);
2833        if (!date.isValid()) {
2834            return null;
2835        }
2836        return date.format('MMMM Do, YYYY');
2837    };
2838});
2839appFilters.filter('ordinalDateWithTime', function ($log) {
2840    $log.getInstance('ordinalDateWithTime');
2841    return function (input) {
2842        var date = new Date(input);
2843        date = moment(date);
2844        if (!date.isValid()) {
2845            return null;
2846        }
2847        return date.format('MMMM Do, YYYY (HH:mmA)');
2848    };
2849});
2850;
2851'use strict';
2852var appFilters = angular.module('distanceFilters', []);
2853appFilters.filter('feet2distanceSmart', function (CONFIG, $log, $filter) {
2854    $log = $log.getInstance('feet2distanceSmart');
2855    var system = CONFIG.distanceUnitSystem
2856        ? CONFIG.distanceUnitSystem
2857        : 'imperial';
2858    return function (input, includeUnitLabel) {
2859        if (!angular.isNumber(input) || isNaN(input))
2860            return null;
2861        var includeUnit = includeUnitLabel === false ? false : true;
2862        var unitA = includeUnit ? ' mi' : '';
2863        var unitB = includeUnit ? ' ft' : '';
2864        var result;
2865        if (system === 'imperial') {
2866            var feet = input;
2867            result =
2868                feet > 1000
2869                    ? $filter('number')(feet / 5280, 1) + unitA
2870                    : $filter('number')(feet, 0) + unitB;
2871            result = includeUnit ? result : parseFloat(result);
2872        }
2873        else if (system === 'metric') {
2874            var meters = input.toFixed(3) * 0.3048;
2875            result = $filter('meters2distanceSmart')(meters, includeUnit);
2876        }
2877        return result;
2878    };
2879});
2880appFilters.filter('miles2distanceSmart', function (CONFIG, $log, $filter) {
2881    $log = $log.getInstance('miles2distanceSmart');
2882    var system = angular.isString(CONFIG.distanceUnitSystem) &&
2883        CONFIG.distanceUnitSystem.toLowerCase() === 'metric'
2884        ? 'metric'
2885        : 'imperial';
2886    return function (inputValue, includeUnitLabel) {
2887        var input = parseFloat(inputValue + '');
2888        if (!angular.isNumber(input) || isNaN(input))
2889            return null;
2890        var includeUnit = includeUnitLabel !== false;
2891        var result;
2892        switch (system) {
2893            case 'metric':
2894                var meters = input.toFixed(3) * 1609.34;
2895                result = $filter('meters2distanceSmart')(meters, includeUnit);
2896                break;
2897            case 'imperial':
2898            default:
2899                var feet = input.toFixed(3) * 5280;
2900                result = $filter('feet2distanceSmart')(feet, includeUnit);
2901                break;
2902        }
2903        return result;
2904    };
2905});
2906appFilters.filter('meters2distanceSmart', function (CONFIG, $log, $filter) {
2907    $log = $log.getInstance('meters2distanceSmart');
2908    var system = CONFIG.distanceUnitSystem
2909        ? CONFIG.distanceUnitSystem
2910        : 'imperial';
2911    return function (input, includeUnitLabel) {
2912        if (!angular.isNumber(input) || isNaN(input))
2913            return null;
2914        var includeUnit = includeUnitLabel === false ? false : true;
2915        var unitA = includeUnit ? ' km' : '';
2916        var unitB = includeUnit ? ' m' : '';
2917        var result;
2918        if (system === 'imperial') {
2919            var feet = input.toFixed(3) / 0.3048;
2920            result = $filter('feet2distanceSmart')(feet, includeUnit);
2921        }
2922        else if (system === 'metric') {
2923            var meters = input;
2924            result =
2925                meters > 249
2926                    ? $filter('number')(meters / 1000, 2) + unitA
2927                    : $filter('number')(meters, 0) + unitB;
2928            result = includeUnit ? result : parseFloat(result);
2929        }
2930        return result;
2931    };
2932});
2933appFilters.filter('distance2milesSmart', function (CONFIG, $log, $filter) {
2934    $log = $log.getInstance('distance2milesSmart');
2935    var system = CONFIG.distanceUnitSystem
2936        ? CONFIG.distanceUnitSystem
2937        : 'imperial';
2938    return function (input, includeUnitLabel) {
2939        if (!angular.isNumber(input) || isNaN(input))
2940            return null;
2941        var includeUnit = includeUnitLabel === false ? false : true;
2942        var unitA = includeUnit ? ' mi' : 0;
2943        var result;
2944        if (system === 'imperial') {
2945            result = input + unitA;
2946            result = includeUnit ? result : parseFloat(result);
2947        }
2948        else if (system === 'metric') {
2949            result = (input * 0.621371).toFixed(2) + unitA;
2950            result = includeUnit ? result : parseFloat(result);
2951        }
2952        return result;
2953    };
2954});
2955appFilters.filter('longestStretch', function ($rootScope) {
2956    return function (input) {
2957        var lowest = Number.POSITIVE_INFINITY;
2958        var highest = Number.NEGATIVE_INFINITY;
2959        var tmp, highString, lowString;
2960        angular.forEach(input.result.legs, function (leg) {
2961            for (var i = leg.steps.length - 1; i >= 0; i--) {
2962                tmp = leg.steps[i].distance;
2963                if (tmp < lowest) {
2964                    lowest = tmp;
2965                    lowString = leg.steps[i].streetName.toString() || null;
2966                }
2967                if (tmp > highest) {
2968                    highest = tmp;
2969                    highString = leg.steps[i].streetName.toString() || null;
2970                }
2971            }
2972        });
2973        return highString;
2974    };
2975});
2976;
2977'use strict';
2978var appFilters = angular.module('appFilters', [
2979    'stringFilters',
2980    'dateFilters',
2981    'timeFilters',
2982    'distanceFilters',
2983    'currencyFilters',
2984    'numberFilters',
2985]);
2986appFilters.filter('conditionalTitleCase', [
2987    '$filter',
2988    function ($filter) {
2989        return function (input) {
2990            if (!input) {
2991                return input;
2992            }
2993            var words = input.split(' ');
2994            if (words[0].toLowerCase() === 'etc') {
2995                words[0] = words[0].toUpperCase();
2996                for (var i = 1; i < words.length; i++) {
2997                    words[i] =
2998                        words[i].charAt(0).toUpperCase() + words[i].substr(1).toLowerCase();
2999                }
3000                return words.join(' ');
3001            }
3002            else {
3003                return $filter('titleCase')(input);
3004            }
3005        };
3006    },
3007]);
3008appFilters.filter('carpoolAddress', function ($rootScope) {
3009    return function (input) {
3010        if (!angular.isString(input))
3011            return input;
3012        input = input.trim();
3013        input = input
3014            .replace(/(#|APARTMENT|APT|BASEMENT|BSMT|BUILDING|BLDG|DEPARTMENT|DEPT|FLOOR|FL|FRONT|FRNT|HANGAR|HNGR|LOBBY|LBBY|LOT|LOWER|LOWR|OFFICE|OFC|PENTHOUSE|PH|PIER|REAR|ROOM|RM|SIDE|SLIP|SPACE|SPC|STOP|SUITE|STE|TRAILER|TRLR|UNIT|UPPER|UPPR)\.?\d+(,(?=\s\d))?/gi, '')
3015            .trim();
3016        input = input
3017            .replace(/^[A-Z]*\d+[A-Z]*\-*\d*\s?[A-Z]{0,2}(?=\s)/i, '')
3018            .trim();
3019        if ($rootScope.CONFIG && $rootScope.CONFIG.carpoolAddressRegex)
3020            input = input.replace($rootScope.CONFIG.carpoolAddressRegex, '').trim();
3021        return input;
3022    };
3023});
3024appFilters.filter('camelCaseToWords', function () {
3025    return function (input) {
3026        return input.replace(/([A-Z])/g, ' $1').replace(/^./, function (input) {
3027            return input.toUpperCase();
3028        });
3029    };
3030});
3031appFilters.filter('percentage', function () {
3032    return function (input) {
3033        var rounded = Math.round(input * 10000) / 100;
3034        if (rounded == NaN) {
3035            return '';
3036        }
3037        var percentage = '' + rounded + '%';
3038        return percentage;
3039    };
3040});
3041appFilters.filter('propertyExists', function () {
3042    return function (items, property) {
3043        var arrayToReturn = [];
3044        for (var i = 0; i < items.length; i++) {
3045            var test = property !== undefined ? items[i][property] : items[i];
3046            if (test !== undefined && test !== null) {
3047                arrayToReturn.push(items[i]);
3048            }
3049        }
3050        return arrayToReturn;
3051    };
3052});
3053appFilters.filter('oldFilter', function () {
3054    return function (array, expression, comparator) {
3055        if (!_.isArray(array))
3056            return array;
3057        function getter(obj, path, bindFnToScope) {
3058            if (!path)
3059                return obj;
3060            var keys = path.split('.');
3061            var key;
3062            var lastInstance = obj;
3063            var len = keys.length;
3064            for (var i = 0; i < len; i++) {
3065                key = keys[i];
3066                if (obj) {
3067                    obj = (lastInstance = obj)[key];
3068                }
3069            }
3070            if (!bindFnToScope && _.isFunction(obj)) {
3071                return _.bind(lastInstance, obj);
3072            }
3073            return obj;
3074        }
3075        var comparatorType = typeof comparator, predicates = [];
3076        predicates.check = function (value) {
3077            for (var j = 0; j < predicates.length; j++) {
3078                if (!predicates[j](value)) {
3079                    return false;
3080                }
3081            }
3082            return true;
3083        };
3084        if (comparatorType !== 'function') {
3085            if (comparatorType === 'boolean' && comparator) {
3086                comparator = function (obj, text) {
3087                    return angular.equals(obj, text);
3088                };
3089            }
3090            else {
3091                comparator = function (obj, text) {
3092                    text = ('' + text).toLowerCase();
3093                    return ('' + obj).toLowerCase().indexOf(text) > -1;
3094                };
3095            }
3096        }
3097        var search = function (obj, text) {
3098            if (typeof text == 'string' && text.charAt(0) === '!') {
3099                return !search(obj, text.substr(1));
3100            }
3101            switch (typeof obj) {
3102                case 'boolean':
3103                case 'number':
3104                case 'string':
3105                    return comparator(obj, text);
3106                case 'object':
3107                    switch (typeof text) {
3108                        case 'object':
3109                            return comparator(obj, text);
3110                        default:
3111                            for (var objKey in obj) {
3112                                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
3113                                    return true;
3114                                }
3115                            }
3116                            break;
3117                    }
3118                    return false;
3119                case 'array':
3120                    for (var i = 0; i < obj.length; i++) {
3121                        if (search(obj[i], text)) {
3122                            return true;
3123                        }
3124                    }
3125                    return false;
3126                default:
3127                    return false;
3128            }
3129        };
3130        switch (typeof expression) {
3131            case 'boolean':
3132            case 'number':
3133            case 'string':
3134                expression = {
3135                    $: expression,
3136                };
3137            case 'object':
3138                for (var key in expression) {
3139                    (function (path) {
3140                        if (typeof expression[path] == 'undefined')
3141                            return;
3142                        predicates.push(function (value) {
3143                            return search(path == '$' ? value : getter(value, path), expression[path]);
3144                        });
3145                    })(key);
3146                }
3147                break;
3148            case 'function':
3149                predicates.push(expression);
3150                break;
3151            default:
3152                return array;
3153        }
3154        var filtered = [];
3155        for (var j = 0; j < array.length; j++) {
3156            var value = array[j];
3157            if (predicates.check(value)) {
3158                filtered.push(value);
3159            }
3160        }
3161        return filtered;
3162    };
3163});
3164appFilters.filter('offset', function () {
3165    return function (input, start) {
3166        start = parseInt(start, 10);
3167        return input ? input.slice(start) : null;
3168    };
3169});
3170appFilters.filter('element', function () {
3171    return function (input, method, argOne) {
3172        var reflect;
3173        if (angular.isDefined(argOne)) {
3174            reflect = angular.element(input)[method](argOne);
3175        }
3176        else {
3177            reflect = angular.element(input)[method]();
3178        }
3179        return reflect;
3180    };
3181});
3182appFilters.filter('orderObjectBy', function () {
3183    return function (items, field, reverse) {
3184        var filtered = [];
3185        angular.forEach(items, function (item) {
3186            filtered.push(item);
3187        });
3188        filtered.sort(function (a, b) {
3189            return a[field] > b[field] ? 1 : -1;
3190        });
3191        if (reverse)
3192            filtered.reverse();
3193        return filtered;
3194    };
3195});
3196appFilters.filter('typeof', function ($log, $filter) {
3197    $log = $log.getInstance('typeofFilter');
3198    return function (input, logType) {
3199        if (!_.includes(['log', 'warn', 'info', 'error'], logType))
3200            logType = 'debug';
3201        $log[logType]('typeof input', typeof input, input, arguments);
3202        var theReturn = [typeof input, input];
3203        return theReturn;
3204    };
3205});
3206appFilters.filter('log', function ($log, $filter) {
3207    $log = $log.getInstance('typeofFilter');
3208    return function (input, logType) {
3209        if (!_.includes(['log', 'warn', 'info', 'error'], logType))
3210            logType = 'debug';
3211        $log[logType]('$filter:log.' + logType, ' typeof input:', typeof input, input, arguments);
3212        return input;
3213    };
3214});
3215appFilters.filter('diffToHTML', function () {
3216    return function (diff) {
3217        return jsondiffpatch.formatters.html.format(diff);
3218    };
3219});
3220appFilters.filter('display3Decimals', function () {
3221    return function (input) {
3222        if (angular.isNumber(input)) {
3223            var decimalPart = (input % 1).toFixed(3).substring(2);
3224            if (decimalPart === '000') {
3225                return input.toFixed(0);
3226            }
3227            else if (decimalPart.charAt(2) === '0') {
3228                return input.toFixed(2).replace(/\.?0+$/, '');
3229            }
3230            else if (decimalPart.charAt(1) === '0') {
3231                return input.toFixed(1).replace(/\.?0+$/, '');
3232            }
3233            else {
3234                return input.toFixed(3).replace(/\.?0+$/, '');
3235            }
3236        }
3237        else {
3238            return input;
3239        }
3240    };
3241});
3242appFilters.filter('excludeHiddenNetworks', function () {
3243    return function (networks) {
3244        return networks.filter(function (network) {
3245            return !network.hiddenFromUsers;
3246        });
3247    };
3248});
3249;
3250'use strict';
3251var appFilters = angular.module('numberFilters', []);
3252appFilters.filter('pounds2volumeSmart', function (CONFIG, $log, $filter) {
3253    $log.getInstance('pounds2volumeSmart');
3254    var system = CONFIG.volumeUnitSystem ? CONFIG.volumeUnitSystem : 'imperial';
3255    var decimalPosition = function (number) {
3256        return number.toFixed(1) % 1 !== 0 ? 1 : 0;
3257    };
3258    var formatValue = function (value, string) {
3259        if (value.toFixed(1) / 1 === 1) {
3260            string = string.replace(/s+$/, '');
3261        }
3262        return $filter('number')(value, decimalPosition(value)) + string;
3263    };
3264    var doImperialConversion = function (pounds) {
3265        return pounds > 9999
3266            ? formatValue(pounds / 2000, ' tons')
3267            : formatValue(pounds, ' lbs');
3268    };
3269    var doMetricConversion = function (pounds) {
3270        var kg = (pounds * 0.453592).toFixed(2) + 0.0;
3271        var metricTons = kg / 1000;
3272        return kg > 250
3273            ? formatValue(metricTons, ' tons')
3274            : formatValue(Number(kg), ' kg');
3275    };
3276    return function (input) {
3277        if (!angular.isNumber(input) || isNaN(input)) {
3278            return null;
3279        }
3280        input = input.toFixed(2) * 1;
3281        return system === 'imperial'
3282            ? doImperialConversion(input)
3283            : doMetricConversion(input);
3284    };
3285});
3286appFilters.filter('shortNumber', function ($log) {
3287    $log.getInstance('shortNumber');
3288    return function (input) {
3289        if (!angular.isNumber(input)) {
3290            return null;
3291        }
3292        var value = Math.round(input);
3293        var newValue = value;
3294        if (value >= 1000) {
3295            var suffixes = [
3296                '',
3297                'k',
3298                ' Million',
3299                ' Billion',
3300                ' Trillion',
3301                ' Quadrillion',
3302                ' Quintillion',
3303            ];
3304            var suffixNum = Math.floor(('' + value).length / 3);
3305            var shortValue = '';
3306            for (var precision = 2; precision >= 1; precision--) {
3307                shortValue = parseFloat((suffixNum !== 0
3308                    ? value / Math.pow(1000, suffixNum)
3309                    : value).toPrecision(precision));
3310                var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g, '');
3311                if (dotLessShortValue.length <= 2) {
3312                    break;
3313                }
3314            }
3315            newValue = shortValue + suffixes[suffixNum];
3316        }
3317        return newValue ? newValue : value;
3318    };
3319});
3320appFilters.filter('round2NearestQuarterDecimal', function () {
3321    return function (input) {
3322        var float = parseFloat(input), isWholeNum = float % 1 === 0, decimal;
3323        if (!input || isNaN(float)) {
3324            return input;
3325        }
3326        if (isWholeNum) {
3327            return float;
3328        }
3329        decimal = (input % 1).toFixed(2).substring(2);
3330        if (decimal < 25)
3331            float = Math.floor(float);
3332        else if (decimal >= 25 && decimal < 50)
3333            float = parseFloat(Math.floor(float) + '.25');
3334        else if (decimal >= 50 && decimal < 75)
3335            float = parseFloat(Math.floor(float) + '.50');
3336        else if (decimal > 75)
3337            float = Math.round(float);
3338        return float;
3339    };
3340});
3341appFilters.filter('percentDiff', function () {
3342    return function (a, b) {
3343        if (!a || !b || a === 0) {
3344            return '0 %';
3345        }
3346        var percent = Math.floor((b / a) * 100 - 100);
3347        return percent === 0 ? '0 %' : percent + ' %';
3348    };
3349});
3350appFilters.filter('numberSmart', function ($filter) {
3351    return function (inputNumber, decimalLimit) {
3352        if (isNaN(inputNumber)) {
3353            return '';
3354        }
3355        if (decimalLimit === undefined) {
3356            decimalLimit = 2;
3357        }
3358        var formattedNumber = $filter('number')(inputNumber, decimalLimit);
3359        return _.replace(formattedNumber, /\.?0*$/, '');
3360    };
3361});
3362;
3363'use strict';
3364var appFilters = angular.module('stringFilters', []);
3365appFilters.filter('capitalizeFirstLetter', function () {
3366    return function (text) {
3367        if (!angular.isString(text)) {
3368            return text;
3369        }
3370        return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
3371    };
3372});
3373appFilters.filter('titleCase', function () {
3374    return function (input) {
3375        if (angular.isNumber(input))
3376            input = input.toString();
3377        if (!angular.isString(input) && !angular.isArray(input))
3378            return input;
3379        function upperFirstLetter(str) {
3380            return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
3381        }
3382        var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i;
3383        var words = !angular.isArray(input) ? input.split(' ') : input;
3384        angular.forEach(words, function (w, i) {
3385            words[i] =
3386                i === 0 || words[i].search(smallWords) === -1
3387                    ? upperFirstLetter(words[i])
3388                    : words[i].toLowerCase();
3389        });
3390        return words.join(' ');
3391    };
3392});
3393appFilters.filter('classname', function ($log, $filter) {
3394    $log = $log.getInstance("filter:'classname'");
3395    return function (input) {
3396        if (typeof input !== 'string')
3397            return input;
3398        var firstChar = isNaN(input.charAt(0)) ? '' : '_';
3399        var joinedString = firstChar + input.toLowerCase().replace(/[\.\s]/g, '-');
3400        return joinedString;
3401    };
3402});
3403appFilters.filter('safeString', function ($log) {
3404    $log = $log.getInstance("filter:'safeString'");
3405    return function (inputString, joinString) {
3406        if (typeof inputString !== 'string')
3407            return inputString;
3408        var validCharacters = new RegExp(/-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g);
3409        var joinCharacters = typeof joinString !== 'string' ? '_' : joinString;
3410        var firstCharacter = isNaN(inputString.charAt(0)) ? '' : '_';
3411        var stringArray = (firstCharacter + inputString).match(validCharacters);
3412        var joined = stringArray ? stringArray.join(joinCharacters) : '';
3413        return joined;
3414    };
3415});
3416appFilters.filter('toLowerCase', function ($log) {
3417    $log = $log.getInstance("filter:'toLowerCase'");
3418    return function (input) {
3419        return !angular.isString(input) ? input : input.toLowerCase();
3420    };
3421});
3422appFilters.filter('toUpperCase', function ($log) {
3423    $log = $log.getInstance("filter:'toUpperCase'");
3424    return function (input) {
3425        return !angular.isString(input) ? input : input.toUpperCase();
3426    };
3427});
3428appFilters.filter('htmlToText', function () {
3429    return function (input) {
3430        return String(input).replace(/<[^>]+>/gm, '');
3431    };
3432});
3433appFilters.filter('stringReplace', function ($log) {
3434    $log = $log.getInstance("filter:'stringReplace'");
3435    return function (input, oldString, newString) {
3436        if (typeof input !== 'string')
3437            return null;
3438        var result = input.replace(oldString, newString);
3439        return result;
3440    };
3441});
3442appFilters.filter('limitText', function ($log) {
3443    $log = $log.getInstance('filter:limitText');
3444    return function (_value, _arg1_wordwise, _arg2_max, _arg3_tail) {
3445        if (!_value)
3446            return '';
3447        var defaults = {
3448            wordwise: true,
3449            max: 35,
3450            tail: '…',
3451        };
3452        var tail = _arg3_tail || _arg2_max || _arg1_wordwise || defaults.tail;
3453        if (!_.isString(tail))
3454            tail = defaults.tail;
3455        var max = parseInt(_arg2_max);
3456        if (_.isNaN(max))
3457            max = parseInt(_arg1_wordwise);
3458        if (_.isNaN(max))
3459            max = parseInt(defaults.max);
3460        var wordwise = _arg1_wordwise === false ? false : defaults.wordwise;
3461        var value = _value;
3462        if (value.length <= max)
3463            return value;
3464        value = value.substr(0, max);
3465        if (wordwise) {
3466            var lastspace = value.lastIndexOf(' ');
3467            if (lastspace !== -1) {
3468                value = value.substr(0, lastspace);
3469            }
3470        }
3471        return value + tail;
3472    };
3473});
3474appFilters.filter('modesToLabels', function () {
3475    function translateMode(mode) {
3476        var translation = _.find(CONFIG.modes, function (m) {
3477            return m.value === mode;
3478        });
3479        return translation && translation.label ? translation.label : mode;
3480    }
3481    return function (modes) {
3482        if (modes && angular.isArray(modes)) {
3483            return _.map(modes, function (mode) {
3484                return translateMode(mode);
3485            }).join(', ');
3486        }
3487        else if (modes && angular.isString(modes)) {
3488            return translateMode(modes);
3489        }
3490        else {
3491            return '';
3492        }
3493    };
3494});
3495appFilters.filter('joinByKey', function () {
3496    return function (array, key) {
3497        if (array === void 0) { array = []; }
3498        return _.map(array, key).join(', ');
3499    };
3500});
3501appFilters.filter('locationToString', function (LocationService) {
3502    return function (location) {
3503        var label = _.get(location, 'properties.label');
3504        var coords = _.get(location, 'geometry.coordinates', []);
3505        if (!label || !coords.length)
3506            return;
3507        return LocationService.locationToString({
3508            label: label,
3509            lng: coords[0],
3510            lat: coords[1],
3511        });
3512    };
3513});
3514;
3515'use strict';
3516var appFilters = angular.module('timeFilters', []);
3517appFilters.filter('min2hoursSmart', function () {
3518    return function (input) {
3519        if (!angular.isNumber(input) || isNaN(input))
3520            return null;
3521        input = Math.round(input);
3522        if (input < 1)
3523            return '< 1 min';
3524        return input < 60
3525            ? input.toFixed() + ' min'
3526            : Math.floor(input / 60) + ' hr ' + (input % 60).toFixed() + ' min';
3527    };
3528});
3529appFilters.filter('trimLeftZeros', function ($rootScope) {
3530    return function (input) {
3531        if (!angular.isString(input))
3532            return input;
3533        var formattedText = input ? input.replace(/^0/, '') : '';
3534        return formattedText;
3535    };
3536});
3537appFilters.filter('normalizeDateString', function ($filter) {
3538    return function (input) {
3539        var momentDate = moment(input).utc();
3540        var day = '<span isolate>' + momentDate.format('dddd') + '</span>';
3541        var month = '<span isolate>' + momentDate.format('MMMM') + '</span>';
3542        var date = '<var>' + momentDate.format('D') + '</var>';
3543        return day + ', ' + month + ' ' + date;
3544    };
3545});
3546appFilters.filter('tzDate', function ($filter, CONFIG) {
3547    return function (input, format, tz) {
3548        format = format || 'medium';
3549        tz = tz || -moment().utcOffset();
3550        var result = $filter('date')(input, format, tz);
3551        return result;
3552    };
3553});
3554appFilters.filter('momentRoundForward', function ($log) {
3555    $log = $log.getInstance("filter:'momentRoundForward'");
3556    return function momentRoundForward(inputStringOrMoment, precision, key, momentFormat) {
3557        if (window.moment &&
3558            (!moment().round || !moment().ceil || !moment().floor)) {
3559            (function () {
3560                moment.fn.round = function (precision, key, direction) {
3561                    if (typeof direction === 'undefined') {
3562                        direction = 'round';
3563                    }
3564                    var keys = ['Hours', 'Minutes', 'Seconds', 'Milliseconds'];
3565                    var maxValues = [24, 60, 60, 1000];
3566                    key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
3567                    if (key.indexOf('s', key.length - 1) === -1) {
3568                        key += 's';
3569                    }
3570                    var value = 0;
3571                    var rounded = false;
3572                    var subRatio = 1;
3573                    var maxValue;
3574                    for (var i in keys) {
3575                        var k = keys[i];
3576                        if (k === key && typeof this._d['get' + key] === 'function') {
3577                            value = this._d['get' + key]();
3578                            maxValue = maxValues[i];
3579                            rounded = true;
3580                        }
3581                        else if (rounded && typeof this._d['get' + k] === 'function') {
3582                            subRatio *= maxValues[i];
3583                            value += this._d['get' + k]() / subRatio;
3584                            this._d['set' + k](0);
3585                        }
3586                    }
3587                    value = Math[direction](value / precision) * precision;
3588                    value = Math.min(value, maxValue);
3589                    this._d['set' + key](value);
3590                    return this;
3591                };
3592                moment.fn.ceil = function (precision, key) {
3593                    return this.round(precision, key, 'ceil');
3594                };
3595                moment.fn.floor = function (precision, key) {
3596                    return this.round(precision, key, 'floor');
3597                };
3598            })();
3599        }
3600        if (!window.moment || !window.moment().round) {
3601            return inputStringOrMoment;
3602        }
3603        var result = inputStringOrMoment;
3604        var inputWasaString = _.isString(inputStringOrMoment);
3605        var precision = precision || 15;
3606        var key = key || 'minutes';
3607        var momentFormat = momentFormat || 'hh:mm A';
3608        if (inputWasaString)
3609            result = moment(result, momentFormat);
3610        if (!moment.isMoment(result) || !result.isValid()) {
3611            return inputStringOrMoment;
3612        }
3613        result = result.round(precision, key, 'ceil');
3614        if (inputWasaString)
3615            result = result.format(momentFormat);
3616        return result;
3617    };
3618});
3619;
3620'use strict';
3621angular
3622    .module('contentManagement', [])
3623    .run(function ($rootScope, ContentManagementService) {
3624    var tokenWatcher = $rootScope.$watch('session', function (session) {
3625        if (session && session.token) {
3626            ContentManagementService.loadContent();
3627            tokenWatcher();
3628        }
3629    });
3630})
3631    .factory('ContentManagementService', function ($vhttp, $rootScope) {
3632    var contentMap = new Map();
3633    var loaded = false;
3634    var hasError = false;
3635    function getContent(key) {
3636        return contentMap.get(key);
3637    }
3638    function loadContent() {
3639        if (loaded)
3640            loaded = false;
3641        return $vhttp
3642            .get('/api/v1/cms/content-collection/preloaded')
3643            .then(function (content) {
3644            contentMap = new Map();
3645            for (var key in content) {
3646                contentMap.set(key, content[key]);
3647            }
3648            loaded = true;
3649        })
3650            .catch(function (err) {
3651            console.error('Error loading content', err);
3652            hasError = true;
3653        });
3654    }
3655    function pullForContentKey(key) {
3656        return new Promise(function (resolve, reject) {
3657            if (loaded) {
3658                return resolve(getContent(key));
3659            }
3660            if (hasError) {
3661                return reject('Content keys unavailable.');
3662            }
3663            return registerContentKeyListener(key, resolve, reject);
3664        });
3665    }
3666    var timer = null;
3667    var contentWatcher = null;
3668    function registerContentKeyListener(key, resolve, reject) {
3669        if (contentWatcher)
3670            return;
3671        timer = setTimeout(function () {
3672            destroyContentWatcher();
3673            reject('Content has timed out');
3674        }, 10000);
3675        contentWatcher = $rootScope.$watch(function () { return ContentManagementService.isLoaded(); }, function (loaded) {
3676            if (loaded) {
3677                destroyTimer();
3678                destroyContentWatcher();
3679                resolve(getContent(key));
3680            }
3681        });
3682    }
3683    function destroyContentWatcher() {
3684        if (contentWatcher)
3685            contentWatcher();
3686        contentWatcher = null;
3687    }
3688    function destroyTimer() {
3689        if (timer)
3690            clearTimeout(timer);
3691        timer = null;
3692    }
3693    return {
3694        getContent: getContent,
3695        loadContent: loadContent,
3696        fetchContentKey: pullForContentKey,
3697        isLoaded: function () {
3698            return loaded;
3699        },
3700    };
3701});
3702;
3703'use strict';
3704var appServices = angular.module('elementServices', []);
3705appServices.service('elementHelper', function () {
3706    var service = this;
3707    this.getNavHeight = function () {
3708        var nav = $('.navbar'), sub = nav.parent().find('.subsite-navbar'), top = ~~(nav.outerHeight() + sub.outerHeight());
3709        nav = sub = null;
3710        return top;
3711    };
3712    this.getFooterHeight = function () {
3713        var footer = $('.layout-footer');
3714        if (footer.is(':visible')) {
3715            return footer.outerHeight() || 0;
3716        }
3717        else {
3718            return 0;
3719        }
3720    };
3721    this.scrollToElement = function (element, offset, speed) {
3722        offset = offset || this.getNavHeight();
3723        speed = speed || 500;
3724        $('html, body').animate({
3725            scrollTop: $(element).offset().top - offset,
3726        }, speed);
3727    };
3728    this.isScrolledBtm = function (offset) {
3729        offset = offset || 10;
3730        return ($(document).height() - $(window).height() <=
3731            $(window).scrollTop() + offset);
3732    };
3733    this.isOnSmallScreen = function () {
3734        return $(window).innerWidth() < 992;
3735    };
3736    return this;
3737});
3738;
3739'use strict';
3740var appServices = angular.module('ErrorResolvingServices', []);
3741appServices.service('AccountResolvingService', function (Dialogs) {
3742    function handleError(error, callback) {
3743        var _a;
3744        var message;
3745        var errorData = !!error.data;
3746        var emailError = errorData && error.data.errors && error.data.errors.email;
3747        var uniqueError = emailError
3748            ? error.data.errors.email.kind === 'unique'
3749            : false;
3750        var restrictedDomain = emailError
3751            ? error.data.errors.email.message === 'restrictedDomains'
3752            : false;
3753        var genericLoginErrorMessage = 'Please check your email and password and try again';
3754        var genericErrorMessage = 'There was a problem completing your request';
3755        var incorrectDomainMessage = emailError
3756            ? error.data.errors.email.value.replace(/.*@/, '') +
3757                ' is not an authorized email domain'
3758            : '';
3759        var emailTakenMessage = emailError
3760            ? 'The email ' + error.data.errors.email.value + ' is already in use. '
3761            : '';
3762        var emailTakenPasswordMessage = emailTakenMessage + 'Please try resetting your password';
3763        var emailTakenPasswordResendMessage = emailTakenPasswordMessage + ' or resending your confirmation email';
3764        var accountNotActivatedMessage = 'The account provided has not been activated yet, you can activate it by resending your confirmation email.';
3765        if (errorData) {
3766            if (uniqueError) {
3767                if (uniqueError && CONFIG.requireEmailConfirmation) {
3768                    message = emailTakenPasswordResendMessage;
3769                }
3770                else {
3771                    message = emailTakenMessage;
3772                }
3773            }
3774            else if (restrictedDomain) {
3775                message = incorrectDomainMessage;
3776            }
3777        }
3778        else {
3779            var errorName = (_a = error.error) !== null && _a !== void 0 ? _a : error.name;
3780            if (errorName === 'InvalidCredentials') {
3781                message = genericLoginErrorMessage;
3782            }
3783            else if (errorName === 'AccountLocked') {
3784                message = error.message;
3785            }
3786            else if (errorName === 'AccountNotActivated') {
3787                message = accountNotActivatedMessage;
3788            }
3789        }
3790        if (callback) {
3791            callback(message !== null && message !== void 0 ? message : genericErrorMessage);
3792        }
3793        else {
3794            Dialogs.alert(message !== null && message !== void 0 ? message : genericErrorMessage);
3795        }
3796    }
3797    return {
3798        handleError: handleError,
3799    };
3800});
3801;
3802'use strict';
3803var appTools = angular.module('AppTools', []);
3804appTools.factory('EnabledPrograms', function () {
3805    var blueprints = [
3806        {
3807            name: 'LeftColumn',
3808            img: CONFIG.navbarLanguage.programsLeftColumnImg ||
3809                'img/parkside/bicycle.png',
3810            entryPoint: CONFIG.navbarLanguage.programsLeftColumnEntryPoint || '#',
3811            link: CONFIG.navbarLanguage.programsLeftColumnLink,
3812            buttonText: CONFIG.navbarLanguage.programsLeftColumnButtonText || 'Go!',
3813            static: CONFIG.navbarLanguage.programsLeftColumnStatic,
3814            isVisible: function () {
3815                return !CONFIG.hideDidYouKnowNavTab;
3816            },
3817        },
3818        {
3819            name: 'Events',
3820            img: 'img/parkside/bicycle.png',
3821            entryPoint: 'events.list',
3822            buttonText: 'Go!',
3823            isVisible: function () {
3824                return CONFIG.showEventsProgramsNavTab;
3825            },
3826        },
3827        {
3828            name: 'PointPrograms',
3829            entryPoint: "incentives.list({tab:'points'})",
3830            buttonText: 'Go!',
3831            isVisible: function () {
3832                return !CONFIG.rewardsEnabled && !CONFIG.hidePointsProgramsNavTab;
3833            },
3834        },
3835        {
3836            name: 'Challenges',
3837            img: 'img/parkside-images/car-leaf-trunk.png',
3838            entryPoint: 'challenges.list',
3839            buttonText: 'Go!',
3840            isVisible: function () {
3841                return CONFIG.challengesV2Enabled && !CONFIG.hideChallengesNavTab;
3842            },
3843        },
3844        {
3845            name: 'Incentives',
3846            entryPoint: "incentives.list({tab:'available'})",
3847            buttonText: 'Go!',
3848            isVisible: function () {
3849                return (!CONFIG.rewardsEnabled &&
3850                    CONFIG.incentivesEnabled &&
3851                    !CONFIG.hideIncentivesNavTab);
3852            },
3853        },
3854        {
3855            name: 'Rewards',
3856            img: 'img/parkside-images/giftbox.svg',
3857            entryPoint: 'rewards',
3858            buttonText: 'Go!',
3859            isVisible: function () {
3860                return CONFIG.rewardsEnabled && !CONFIG.navarProgramsHideRewards;
3861            },
3862        },
3863        {
3864            name: 'ERH',
3865            img: 'img/parkside-images/pointprogram.svg',
3866            entryPoint: CONFIG.navbarProgramsERHEntryPoint,
3867            buttonText: CONFIG.navbarLanguage.programsERHButtonText,
3868            isVisible: function () {
3869                return CONFIG.navbarProgramsERH;
3870            },
3871        },
3872    ];
3873    function getComplexConfigValue(name, type) {
3874        var description = CONFIG.navbarLanguage['programs' + name + 'Paragraph'];
3875        return _.isArray(description) ? _.sample(description) : description;
3876    }
3877    function make(program) {
3878        return _.merge(program, {
3879            header: CONFIG.navbarLanguage['programs' + program.name + 'Header'],
3880            paragraph: getComplexConfigValue(program.name, 'Paragraph'),
3881        });
3882    }
3883    function blueprintFactory() {
3884        return blueprints
3885            .filter(function (blueprint) {
3886            return blueprint.isVisible();
3887        })
3888            .map(function (program) {
3889            return make(program);
3890        });
3891    }
3892    return blueprintFactory;
3893});
3894appTools.service('EnabledTools', function ($rootScope) {
3895    var $instance = this;
3896    $instance.getCategories = function () {
3897        return _.groupBy($rootScope.enabledTools, function (tool) {
3898            return tool.category;
3899        });
3900    };
3901    $instance.getParentStates = function () {
3902        var uniqueParentNames = ['admin'];
3903        $rootScope.enabledTools.forEach(function (tool) {
3904            var parent = tool.baseRoute.split('.')[0];
3905            if (uniqueParentNames.indexOf(parent) < 0) {
3906                uniqueParentNames.push(parent);
3907            }
3908        });
3909        return uniqueParentNames;
3910    };
3911    return $instance;
3912});
3913;
3914'use strict';
3915var appServices = angular.module('appServices', [
3916    'ErrorResolvingServices',
3917    'elementServices',
3918    'AppTools',
3919    'contentManagement',
3920]);
3921appServices.service('SessionUserDataService', function ($rootScope, $log, $http, LocationService, $timeout) {
3922    $log = $log.getInstance('SessionUserDataService');
3923    $rootScope.$watch('session.user', function (user) {
3924        if (user) {
3925            sessionUserData.setUser(user);
3926        }
3927        else {
3928            sessionUserData.reset();
3929        }
3930    });
3931    var SessionUser = function () {
3932        this.reset();
3933        $rootScope.$emit('resetUserData', this);
3934    };
3935    SessionUser.prototype.setUser = function (user) {
3936        if (user !== this.user) {
3937            this.user = user;
3938            this.updateUserData();
3939        }
3940    };
3941    SessionUser.prototype.reset = function () {
3942        this.user = undefined;
3943        this.tripplans = [];
3944        this.updateTripplans = SessionUser.getUpdateFn(this, 'tripplans');
3945        this.tripsearches = [];
3946        this.updateTripsearches = SessionUser.getUpdateFn(this, 'tripsearches');
3947        this.carpoolmessages = [];
3948        this.updateCarpoolmessages = SessionUser.getUpdateFn(this, 'carpoolmessages');
3949        this.managednetworks = [];
3950        this.updateManagednetworks = SessionUser.getUpdateFn(this, 'managednetworks');
3951        this.vanpools = [];
3952        this.updateVanpools = SessionUser.getUpdateFn(this, 'vanpools');
3953        this.triplogReport = {};
3954        this.badges = null;
3955        this.updateBadges = SessionUser.getUpdateFn(this, 'badges');
3956    };
3957    SessionUser.prototype.updateTriplogReport = function () {
3958        var self = this;
3959        $http({
3960            url: '/api/v1/triplogreports/user/' + this.user._id,
3961            method: 'GET',
3962            params: { xcache: new Date() },
3963        }).then(function (data) {
3964            if (data.data)
3965                self.triplogReport = data.data;
3966        });
3967    };
3968    SessionUser.prototype.updateAdvancedManager = function () {
3969        return __awaiter(this, void 0, void 0, function () {
3970            var self, data;
3971            return __generator(this, function (_a) {
3972                switch (_a.label) {
3973                    case 0:
3974                        self = this;
3975                        if (!(CONFIG.premiumNetworks.advancedManagementEnabled &&
3976                            self.user.managedNetworks.length)) return [3, 2];
3977                        return [4, $http.get('/api/v1/ra-connected/is-advanced-manager')];
3978                    case 1:
3979                        data = (_a.sent()).data;
3980                        self.user.isAdvancedManager = data;
3981                        return [3, 3];
3982                    case 2:
3983                        self.user.isAdvancedManager = false;
3984                        _a.label = 3;
3985                    case 3: return [2];
3986                }
3987            });
3988        });
3989    };
3990    SessionUser.prototype.updateAbilities = function (cb) {
3991        if (cb === void 0) { cb = _.noop; }
3992        var onEnd = function () { return $timeout(cb); };
3993        Promise.all([this.updateSchoolpoolAdmin(), this.updateAdvancedManager()])
3994            .then(onEnd)
3995            .catch(onEnd);
3996    };
3997    SessionUser.prototype.updateSchoolpoolAdmin = function () {
3998        return __awaiter(this, void 0, void 0, function () {
3999            var self, data;
4000            return __generator(this, function (_a) {
4001                switch (_a.label) {
4002                    case 0:
4003                        self = this;
4004                        if (!(CONFIG.premiumNetworks.schoolpoolAdminEnabled &&
4005                            self.user.managedNetworks.length)) return [3, 2];
4006                        return [4, $http.get('/api/v1/ra-connected/is-schoolpool-admin')];
4007                    case 1:
4008                        data = (_a.sent()).data;
4009                        self.user.isSchoolpoolAdmin = data;
4010                        return [3, 3];
4011                    case 2:
4012                        self.user.isSchoolpoolAdmin = false;
4013                        _a.label = 3;
4014                    case 3: return [2];
4015                }
4016            });
4017        });
4018    };
4019    SessionUser.prototype.updateUserData = function () {
4020        var self = this;
4021        if (!this.user) {
4022            return;
4023        }
4024        var broadcastUserUpdate = $rootScope.$broadcast.bind($rootScope, 'updateUserData', self);
4025        this.updateManagednetworks();
4026        this.updateVanpools();
4027        this.updateTripplans();
4028        this.updateTripsearches();
4029        this.updateCarpoolmessages();
4030        this.updateTriplogReport();
4031        this.updateBadges();
4032        this.updateAbilities(broadcastUserUpdate);
4033    };
4034    SessionUser.getUpdateFn = function (instance, name) {
4035        return function () {
4036            if (!instance.user)
4037                return;
4038            return instance.user.getList(name, { xcache: new Date() }).then(function (val) {
4039                instance[name] = val;
4040            }, function () {
4041                instance[name] = [];
4042            });
4043        };
4044    };
4045    SessionUser.prototype.getTripplanMatchingTripsearch = function (search) {
4046        var self = this;
4047        $log.debug('getTripplanMatchingTripsearch(search)', search, self.tripplans);
4048        var doesMatch = LocationService.doLocationsMatch;
4049        var matchingPlan = null;
4050        _.forEach(self.tripplans, function (plan) {
4051            if (search.event || plan.relatedEvent) {
4052                if (plan.relatedEvent &&
4053                    search.event &&
4054                    _.isObject(plan.relatedEvent) &&
4055                    plan.relatedEvent._id == search.event)
4056                    matchingPlan = plan;
4057                if (plan.relatedEvent &&
4058                    search.event &&
4059                    _.isString(plan.relatedEvent) &&
4060                    plan.relatedEvent == search.event)
4061                    matchingPlan = plan;
4062                return;
4063            }
4064            if ((doesMatch(plan.from, search.from) &&
4065                doesMatch(plan.to, search.to)) ||
4066                (doesMatch(plan.from, search.to) && doesMatch(plan.to, search.from))) {
4067                matchingPlan = plan;
4068            }
4069        });
4070        $log.debug('getTripplanMatchingTripsearch(search)', 'RESULT', matchingPlan);
4071        return matchingPlan;
4072    };
4073    SessionUser.prototype.getCarpoolmessages = function (tripplan) {
4074        $log.debug('getCarpoolmessages(tripplan)', tripplan._id);
4075        var self = this;
4076        var lastContacted = undefined;
4077        var matchingMessages = [];
4078        _.forEach(self.carpoolmessages, function (message) {
4079            $log.debug('checking carpool', message.trip, tripplan._id, message.trip == tripplan._id);
4080            if (message.trip === tripplan._id)
4081                matchingMessages.push(message);
4082        });
4083        $log.debug('getCarpoolmessages() matchingMessages', lastContacted);
4084        return _.sortBy(matchingMessages, 'created').reverse();
4085    };
4086    SessionUser.prototype.getReduced = function (type, callback) {
4087        if (!this[type] || !this[type].length) {
4088            return [];
4089        }
4090        return _.filter(this[type], callback);
4091    };
4092    var sessionUserData = new SessionUser();
4093    window.SessionUserData = sessionUserData;
4094    return sessionUserData;
4095});
4096appServices.service('Clipboard', function () {
4097    return function (selector, options) {
4098        return new Clipboard(selector || '.btn', options || {});
4099    };
4100});
4101appServices.service('CarpoolContactService', function (SessionUserDataService, $q, $log, Dialogs) {
4102    $log = $log.getInstance('CarpoolContactService');
4103    function getLastContacted(tripplan) {
4104        $log.debug('getLastContacted()', tripplan._id);
4105        var carpoolMessages = SessionUserDataService.getCarpoolmessages(tripplan);
4106        if (carpoolMessages.length)
4107            return carpoolMessages[0].created;
4108        return undefined;
4109    }
4110    function getCarpoolMessages(tripplan) {
4111        $log.debug('getCarpoolMessages()', tripplan._id);
4112        return SessionUserDataService.getCarpoolmessages(tripplan);
4113    }
4114    function sendCarpoolMessage(tripplan, message, type) {
4115        type = type || 'Carpool';
4116        var deferred = $q.defer();
4117        $log.debug('sendCarpoolMessage(tripplan,message)', tripplan, message);
4118        if (message == null) {
4119            Dialog.alert('Please provide a message to send!');
4120            deferred.reject();
4121            return;
4122        }
4123        var success = function (message) {
4124            $log.debug('sendCarpoolMessage() SUCCESS', message);
4125            Dialogs.alert('Your message was sent!');
4126            deferred.resolve(SessionUserDataService.updateCarpoolmessages());
4127        };
4128        var error = function (error) {
4129            $log.debug('sendCarpoolMessage() ERROR', error);
4130            SessionUserDataService.updateCarpoolmessages();
4131            deferred.reject(error);
4132        };
4133        SessionUserDataService.user
4134            .post('carpoolmessages', {
4135            trip: tripplan._id,
4136            message: message,
4137            type: type,
4138        })
4139            .then(success, error);
4140        return deferred.promise;
4141    }
4142    return {
4143        getLastContacted: getLastContacted,
4144        getCarpoolMessages: getCarpoolMessages,
4145        sendCarpoolMessage: sendCarpoolMessage,
4146    };
4147});
4148appServices.service('VanpoolContactService', function (SessionUserDataService, $log, Dialogs) {
4149    $log = $log.getInstance('VanpoolContactService');
4150    function sendVanpoolMessage(vanpool, message) {
4151        $log.debug('sendVanpoolMessage(vanpool,message)', vanpool, message);
4152        if (message == null) {
4153            Dialog.alert('Please provide a message to send!');
4154            return;
4155        }
4156        var success = function (message) {
4157            $log.debug('sendVanpoolMessage() SUCCESS', message);
4158            Dialogs.alert('Your message was sent!');
4159        };
4160        var error = function (error) {
4161            $log.debug('sendVanpoolMessage() ERROR', error);
4162            Dialogs.alert('Oops! There was a problem sending your message. You may try again or c
4162ontact us if the problem persists.');
4163        };
4164        SessionUserDataService.user
4165            .post('vanpoolmessages', {
4166            vanpool: vanpool._id,
4167            message: message,
4168        })
4169            .then(success, error);
4170    }
4171    return {
4172        sendVanpoolMessage: sendVanpoolMessage,
4173    };
4174});
4175appServices.factory('$localstorage', [
4176    '$window',
4177    function ($window) {
4178        return {
4179            set: function (key, value) {
4180                $window.localStorage[key] = value;
4181            },
4182            get: function (key, defaultValue) {
4183                return $window.localStorage[key] || defaultValue;
4184            },
4185            setObject: function (key, value) {
4186                $window.localStorage[key] = JSON.stringify(value);
4187            },
4188            getObject: function (key) {
4189                return JSON.parse($window.localStorage[key] || '{}');
4190            },
4191        };
4192    },
4193]);
4194appServices.factory('$tempStorage', [
4195    '$log',
4196    '$rootScope',
4197    function ($log, $rootScope) {
4198        $log = $log.getInstance('$tempStorage');
4199        $log.debug('Initialized $rootScope.tempStorage = ', $rootScope.tempStorage);
4200        $rootScope.tempStorage = {};
4201        return {
4202            set: function (key, val) {
4203                $log.debug('set', key, val, $rootScope.tempStorage[key]);
4204                return ($rootScope.tempStorage[key] = val);
4205            },
4206            get: function (key, defaultVal) {
4207                $log.debug('get', key, defaultVal, $rootScope.tempStorage[key]);
4208                return $rootScope.tempStorage[key] || defaultVal;
4209            },
4210            check: function (key, val) {
4211                $log.debug('check', key, val, $rootScope.tempStorage[key] === val);
4212                return $rootScope.tempStorage[key] === val;
4213            },
4214        };
4215    },
4216]);
4217appServices.factory('$vhttp', function ($http, vSession) {
4218    var service = {};
4219    service.get = get;
4220    service.post = post;
4221    service.put = put;
4222    service.remove = remove;
4223    return service;
4224    function get(url, queryParams) {
4225        return $http
4226            .get(url, {
4227            params: queryParams,
4228            headers: {
4229                Authorization: 'Bearer ' + vSession.token,
4230                Accept: 'application/json, text/plain, */*',
4231            },
4232        })
4233            .then(function (result) {
4234            return result.data;
4235        });
4236    }
4237    function post(url, data) {
4238        return $http
4239            .post(url, data, {
4240            headers: {
4241                Authorization: 'Bearer ' + vSession.token,
4242                Accept: 'application/json, text/plain, */*',
4243            },
4244        })
4245            .then(function (result) {
4246            return result.data;
4247        });
4248    }
4249    function put(url, data) {
4250        return $http
4251            .put(url, data, {
4252            headers: {
4253                Authorization: 'Bearer ' + vSession.token,
4254                Accept: 'application/json, text/plain, */*',
4255            },
4256        })
4257            .then(function (result) {
4258            return result.data;
4259        });
4260    }
4261    function remove(url, data) {
4262        var options = {
4263            headers: {
4264                Authorization: 'Bearer ' + vSession.token,
4265                Accept: 'application/json, text/plain, */*',
4266            },
4267        };
4268        if (data) {
4269            options.data = data;
4270            options.headers['Content-Type'] = 'application/json';
4271        }
4272        return $http.delete(url, options).then(function (result) {
4273            return result.data;
4274        });
4275    }
4276});
4277appServices.service('mergeModalQue', function ($rootScope, vSession, CarpoolPromptService, $state, CONFIG) {
4278    var self = this;
4279    this.queue = [];
4280    this.startCaptureQue = function () {
4281        if (this.queue.length || !vSession.user)
4282            return;
4283        var promises = [];
4284        if (CONFIG.premiumNetworks.multiPrimaryNetworkEnabled) {
4285            promises.push(self.getIncompleteProfileDef, self.getPrimaryMergeDef, self.getCarpoolOptInDef);
4286        }
4287        promises.push(self.getPostRegistrationDef, self.getCarpoolPromptDef);
4288        self.queue = _.map(promises, function (p) { return p.bind(self); });
4289        _.delay(function () { return self.nextQueue(); }, 500);
4290    };
4291    this.getIncompleteProfileDef = function () {
4292        return __awaiter(this, void 0, void 0, function () {
4293            var modalDef, incompleteProfiles, userProfile, name_1, networkProfileId, netId;
4294            return __generator(this, function (_a) {
4295                switch (_a.label) {
4296                    case 0:
4297                        modalDef = {
4298                            template: 'network-profile-completion-modal.html',
4299                            show: false,
4300                            extraScope: {
4301                                disableModalAutoClose: true,
4302                                disableModalBackgroundClick: true,
4303                            },
4304                        };
4305                        return [4, vSession.user
4306                                .getList('incomplete-profiles')
4307                                .catch(function () { return []; })];
4308                    case 1:
4309                        incompleteProfiles = _a.sent();
4310                        if (incompleteProfiles.length) {
4311                            userProfile = _.first(incompleteProfiles);
4312                            name_1 = _.get(userProfile, 'networkProfile.organizationName');
4313                            networkProfileId = _.get(userProfile, 'networkProfile._id');
4314                            netId = _.get(userProfile, 'networkProfile.network');
4315                            modalDef.extraScope.appUrl = "".concat(location.origin, "/app/my-networks/join-network?name=").concat(name_1, "&id=").concat(netId, "&profile=").concat(networkProfileId);
4316                            modalDef.show = Boolean(netId && name_1);
4317                        }
4318                        return [2, modalDef];
4319                }
4320            });
4321        });
4322    };
4323    this.checkModalPromptField = function (field) {
4324        var path = "customProfileFields.".concat(field);
4325        return _.has(vSession.user, path) && !_.get(vSession.user, path, false);
4326    };
4327    this.getCarpoolOptInDef = function () {
4328        return __awaiter(this, void 0, void 0, function () {
4329            var modalDef, isSharedCommute_1, trips;
4330            return __generator(this, function (_a) {
4331                switch (_a.label) {
4332                    case 0:
4333                        if (!CONFIG.showCarpoolOptInModal) {
4334                            return [2, { show: false }];
4335                        }
4336                        modalDef = {
4337                            template: 'carpool-opt-in-modal',
4338                            show: this.checkModalPromptField('carpoolOptIn'),
4339                            extraScope: {},
4340                        };
4341                        if (!modalDef.show) return [3, 3];
4342                        isSharedCommute_1 = function (trip) {
4343                            var isShared = trip.shared.public ||
4344                                (!trip.shared.public && trip.shared.networks.length);
4345                            var isCommute = !trip.schedule.oneTimeTrip &&
4346                                (trip.tripPreferences.carpool || trip.tripPreferences.bikepool);
4347                            return isShared && isCommute;
4348                        };
4349                        return [4, vSession.user
4350                                .getList('tripplans')
4351                                .then(function (trips) { return _.filter(trips, isSharedCommute_1); })];
4352                    case 1:
4353                        trips = _a.sent();
4354                        modalDef.show = Boolean(trips.length);
4355                        modalDef.extraScope.trips = trips;
4356                        if (!!modalDef.show) return [3, 3];
4357                        return [4, this.updateUserProfileField('carpoolOptIn', true)];
4358                    case 2:
4359                        _a.sent();
4360                        _a.label = 3;
4361                    case 3: return [2, modalDef];
4362                }
4363            });
4364        });
4365    };
4366    this.getPrimaryMergeDef = function () {
4367        return __awaiter(this, void 0, void 0, function () {
4368            var modalDef, showPrimaryMergeNotice, userNets, primaryNets;
4369            return __generator(this, function (_a) {
4370                switch (_a.label) {
4371                    case 0:
4372                        modalDef = {
4373                            template: 'account-merge-modal',
4374                            show: false,
4375                            extraScope: {},
4376                        };
4377                        showPrimaryMergeNotice = this.checkModalPromptField('primaryMergeNotice');
4378                        if (!showPrimaryMergeNotice) return [3, 3];
4379                        return [4, vSession.user.getList('networks')];
4380                    case 1:
4381                        userNets = _a.sent();
4382                        primaryNets = _.filter(userNets, 'capabilities.primaryNetwork');
4383                        modalDef.show = _.size(primaryNets) > 1;
4384                        modalDef.extraScope.userNetworks = primaryNets;
4385                        if (!!modalDef.show) return [3, 3];
4386                        return [4, this.updateUserProfileField('primaryMergeNotice', true)];
4387                    case 2:
4388                        _a.sent();
4389                        _a.label = 3;
4390                    case 3: return [2, modalDef];
4391                }
4392            });
4393        });
4394    };
4395    this.getPostRegistrationDef = function () {
4396        return __awaiter(this, void 0, void 0, function () {
4397            var modalDef, modalShow;
4398            return __generator(this, function (_a) {
4399                modalDef = {
4400                    template: CONFIG.postRegistrationCaptureModal,
4401                    show: false,
4402                    extraScope: {
4403                        disableModalAutoClose: true,
4404                        disableModalBackgroundClick: true,
4405                    },
4406                };
4407                modalDef.onClose = _.bind(function () {
4408                    var _this = this;
4409                    if (!this.user.postRegistrationCapture) {
4410                        this.user.get(vSession.user._id).then(function (user) {
4411                            user.postRegistrationCapture = 'Did Not Respond';
4412                            user.save().then(_this.refresh, _.noop);
4413                        }, _.noop);
4414                    }
4415                }, vSession);
4416                modalShow = CONFIG.postRegistrationCaptureModal &&
4417                    vSession.user &&
4418                    !vSession.user.postRegistrationCapture;
4419                if (modalShow && CONFIG.postRegistrationCaptureModalNetwork)
4420                    modalShow = vSession.user.networks.includes(CONFIG.postRegistrationCaptureModalNetwork);
4421                modalDef.show = modalShow;
4422                if (CONFIG.postRegistrationEligibleNetworks) {
4423                    modalDef.show = !!_.intersection(vSession.UserData.user.networks, CONFIG.postRegistrationEligibleNetworks).length;
4424                }
4425                return [2, modalDef];
4426            });
4427        });
4428    };
4429    this.getCarpoolPromptDef = function () {
4430        return __awaiter(this, void 0, void 0, function () {
4431            var modalDef, _a;
4432            return __generator(this, function (_b) {
4433                switch (_b.label) {
4434                    case 0:
4435                        modalDef = {
4436                            template: CONFIG.postRegistrationCarpoolModal,
4437                            show: false,
4438                            extraScope: {
4439                                disableModalAutoClose: true,
4440                                disableModalBackgroundClick: true,
4441                            },
4442                        };
4443                        if (!(CONFIG.postRegistrationCarpoolModal &&
4444                            vSession.user &&
4445                            !$state.current.name.match(/gotober/))) return [3, 2];
4446                        _a = modalDef;
4447                        return [4, CarpoolPromptService.userNeedsCarpoolPrompt(vSession.user)];
4448                    case 1:
4449                        _a.show = _b.sent();
4450                        _b.label = 2;
4451                    case 2: return [2, modalDef];
4452                }
4453            });
4454        });
4455    };
4456    this.updateUserProfileField = function (field, value) {
4457        return __awaiter(this, void 0, void 0, function () {
4458            return __generator(this, function (_a) {
4459                switch (_a.label) {
4460                    case 0:
4461                        _.set(vSession.user, "customProfileFields.".concat(field), value);
4462                        return [4, vSession.user.put().then(_.noop, _.noop)];
4463                    case 1:
4464                        _a.sent();
4465                        return [2];
4466                }
4467            });
4468        });
4469    };
4470    this.initModalCloseListener = function () {
4471        if (this.modalCloseListener)
4472            return;
4473        this.modalCloseListener = $rootScope.$on('modalHidden', function () {
4474            self.nextQueue();
4475        });
4476    };
4477    this.nextQueue = function () {
4478        return __awaiter(this, void 0, void 0, function () {
4479            var self, nextInQueue, modalDef;
4480            return __generator(this, function (_a) {
4481                switch (_a.label) {
4482                    case 0:
4483                        self = this;
4484                        nextInQueue = _.head(this.queue);
4485                        if (nextInQueue && $rootScope.globalModalVisible)
4486                            return [2];
4487                        if (!nextInQueue) return [3, 2];
4488                        return [4, nextInQueue()];
4489                    case 1:
4490                        modalDef = _a.sent();
4491                        self.queue.shift();
4492                        if (modalDef.show) {
4493                            self.initModalCloseListener();
4494                            $rootScope.globalModalShow(modalDef.template, modalDef.extraScope, modalDef.onClose);
4495                        }
4496                        else {
4497                            self.nextQueue();
4498                        }
4499                        return [3, 3];
4500                    case 2:
4501                        this.endQueue();
4502                        _a.label = 3;
4503                    case 3: return [2];
4504                }
4505            });
4506        });
4507    };
4508    this.endQueue = function () {
4509        this.queue = [];
4510        _.result(this, 'modalCloseListener');
4511    };
4512    return this;
4513});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.